From 35da17edba00b393bbf5c357fd51c7cc994002bf Mon Sep 17 00:00:00 2001 From: avincigu Date: Mon, 21 Oct 2024 11:53:53 +0200 Subject: [PATCH] feat: string manifest builder --- src/GatewayProcessor/GatewayProcessor.ts | 38 +- src/ManifestBuilder/ManifestTypes.ts | 156 +++++ src/ManifestBuilder/StringManifestBuilder.ts | 646 +++++++++++++++++++ src/ManifestBuilder/Utils.ts | 32 + src/StringManifest/MethodsHelper.ts | 182 ------ src/Types/NFT.ts | 41 ++ src/Types/RadixTypes.ts | 22 +- src/index.ts | 7 +- tests/GatewayProcessor.tests.ts | 58 +- 9 files changed, 950 insertions(+), 232 deletions(-) create mode 100644 src/ManifestBuilder/ManifestTypes.ts create mode 100644 src/ManifestBuilder/StringManifestBuilder.ts create mode 100644 src/ManifestBuilder/Utils.ts delete mode 100644 src/StringManifest/MethodsHelper.ts create mode 100644 src/Types/NFT.ts diff --git a/src/GatewayProcessor/GatewayProcessor.ts b/src/GatewayProcessor/GatewayProcessor.ts index 4bc43ca..c6e4f39 100644 --- a/src/GatewayProcessor/GatewayProcessor.ts +++ b/src/GatewayProcessor/GatewayProcessor.ts @@ -29,11 +29,9 @@ import { } from "@radixdlt/radix-engine-toolkit"; import { divideInBatches, parseNonFungibleData, withMaxLoops } from "./Utils"; import { - ComponentAddress, FungibleResource, NonFungibleItem, NonFungibleResource, - ResourceAddress, ResourceInformation, } from "../Types/RadixTypes"; import pLimit from "p-limit"; @@ -273,10 +271,10 @@ export class GatewayProcessor { * @returns A promise resolving to a map containing resource addresses as keys and Resource objects as values. */ async getResourcesInformation( - resource_addresses: ResourceAddress[], + resource_addresses: string[], additional_metadata?: string[], - ): Promise> { - let resource_map = new Map(); + ): Promise> { + let resource_map = new Map(); const batches = divideInBatches(resource_addresses, 20); const limit = pLimit(this._concurrencyLimit); await Promise.all( @@ -297,14 +295,14 @@ export class GatewayProcessor { * @param entity Address of the component. */ async getFungibleResourcesHeldBy( - entity: ComponentAddress, + entity: string, ): Promise { const resp = await this.entityDetails([entity]); const entityState = resp.items[0]; let held_resources: FungibleResource[] = []; - let amount_map = new Map(); - let resources: ResourceAddress[] = []; + let amount_map = new Map(); + let resources: string[] = []; if (entityState.fungible_resources) { entityState.fungible_resources.items.forEach((resource) => { @@ -343,7 +341,7 @@ export class GatewayProcessor { * @param entity Address of the entity. */ async getNonFungibleResourcesHeldBy( - entity: ComponentAddress, + entity: string, ): Promise { const ledger_state = await this.ledgerState(); @@ -421,8 +419,8 @@ export class GatewayProcessor { * @param non_fungible_resource Address of the non-fungible resource. */ async getNonFungibleIdsHeldBy( - entity: ComponentAddress, - non_fungible_resource: ResourceAddress, + entity: string, + non_fungible_resource: string, ): Promise { const ledger_state = await this.ledgerState(); @@ -478,7 +476,7 @@ export class GatewayProcessor { * @param at_ledger_state Optional ledger state when to make the query. */ async getAllNonFungibleIds( - resource_address: ResourceAddress, + resource_address: string, at_ledger_state?: number, ): Promise { const state_version = at_ledger_state @@ -507,7 +505,7 @@ export class GatewayProcessor { * @param at_ledger_state State against which to make the query. */ async getNonFungibleItemsFromIds( - resource_address: ResourceAddress, + resource_address: string, ids: string[], at_ledger_state?: number, ): Promise { @@ -585,7 +583,7 @@ export class GatewayProcessor { * @param resource_address Address of the non-fungible items. * @param ids Ids of the non-fungible items. */ - async getNftOwners(resource_address: ResourceAddress, ids: string[]) { + async getNftOwners(resource_address: string, ids: string[]) { const nft_batches = divideInBatches(ids, 100); const limit = pLimit(this._concurrencyLimit); let return_map = new Map(); @@ -611,10 +609,10 @@ export class GatewayProcessor { * Takes up to 20 resource addresses as input */ private async limitedResourcesInformation( - resource_addresses: ResourceAddress[], + resource_addresses: string[], additional_metadata?: string[], - ): Promise> { - let resource_map = new Map(); + ): Promise> { + let resource_map = new Map(); let resp = await this.entityDetails(resource_addresses); resp.items.forEach((item) => { @@ -802,7 +800,7 @@ export class GatewayProcessor { ); } private async nonFungibleIds( - resource_address: ResourceAddress, + resource_address: string, at_ledger_state: number, cursor?: string, ): Promise { @@ -874,7 +872,7 @@ export class GatewayProcessor { } private async getNonFungibleData( - address: ResourceAddress, + address: string, ids: string[], at_ledger_state?: number, ): Promise { @@ -896,7 +894,7 @@ export class GatewayProcessor { } private async getEntityLocation( - address: ResourceAddress, + address: string, ids: string[], ): Promise { return withMaxLoops( diff --git a/src/ManifestBuilder/ManifestTypes.ts b/src/ManifestBuilder/ManifestTypes.ts new file mode 100644 index 0000000..3302f14 --- /dev/null +++ b/src/ManifestBuilder/ManifestTypes.ts @@ -0,0 +1,156 @@ +import { Decimal } from "../Types/RadixTypes"; +import { NFT } from "../Types/NFT"; + +/** + * Returns a manifest string representation of an address. + * @param address - The address to represent. + * @returns Manifest representation of the address. + */ +export function manifestAddress(address: string): string { + return `Address("${address}")`; +} + +/** + * Returns a manifest string representation of an address reservation. + * @param reservationName - The reservation name. + * @returns Manifest representation of the address reservation. + */ +export function manifestAddressReservation(reservationName: string): string { + return `AddressReservation("${reservationName}")`; +} + +/** + * Returns a manifest representation of an array. + * @param typeName - The type of the items in the array. + * @param content - The array content. + * @returns Manifest representation of the array. + */ +export function manifestArray(typeName: string, content: string[]): string { + return `Array<${typeName}>(${arrayToString(content)})`; +} + +/** + * Returns a manifest string representation of a bucket. + * @param bucketName - The bucket name. + * @returns Manifest representation of the bucket. + */ +export function manifestBucket(bucketName: string): string { + return `Bucket("${bucketName}")`; +} + +/** + * Returns a manifest string representation of a decimal. + * @param {Decimal} decimal - The decimal object. + * @returns Manifest representation of the decimal. + */ +export function manifestDecimal(decimal: Decimal): string { + return `Decimal("${decimal}")`; +} + +/** + * Returns a manifest string representation of an enum. + * @param {number} variantId - The variant ID. + * @param fields - The fields of the enum. + * @returns Manifest representation of the enum. + */ +export function manifestEnum(variantId: number, fields: string[]): string { + return `Enum<${variantId}u8>(${arrayToString(fields)})`; +} + +/** + * Returns a manifest string representation of a non-fungible global ID. + * @param globalId - The global ID. + * @returns Manifest representation of the non-fungible global ID. + */ +export function manifestGlobalId(globalId: string): string { + return `NonFungibleGlobalId("${globalId}")`; +} + +/** + * Returns a manifest string representation of a non-fungible local ID. + * @param id - The local ID. + * @returns Manifest representation of the non-fungible local ID. + */ +export function manifestLocalId(id: string): string { + return `NonFungibleLocalId("${id}")`; +} + +/** + * Returns a manifest string representation of an array of non-fungible local IDs. + * @param ids - Array of local IDs. + * @returns Manifest representation of the local ID array. + */ +export function manifestLocalIdArray(ids: string[]): string { + return manifestArray( + "NonFungibleLocalId", + ids.map((id) => manifestLocalId(id)), + ); +} + +/** + * Returns a manifest string representation of a map. + * @param keyType - The type of the keys. + * @param valueType - The type of the values. + * @param {Map} map - The map to represent. + * @returns Manifest representation of the map. + */ +export function manifestMap( + keyType: string, + valueType: string, + map: Map, +): string { + const content = []; + for (const [key, value] of map.entries()) { + content.push(`${key} => ${value}`); + } + return `Map<${keyType}, ${valueType}>(${arrayToString(content)})`; +} + +/** + * Returns a manifest string representation of a named address. + * @param addressName - The name of the address. + * @returns Manifest representation of the named address. + */ +export function manifestNamedAddress(addressName: string): string { + return `NamedAddress("${addressName}")`; +} + +/** + * Returns a manifest string representation of an NFT. + * @param nft - The NFT object. + * @returns Manifest representation of the NFT. + */ +export function manifestNFT(nft: NFT): string { + return manifestGlobalId(nft.globalId()); +} + +/** + * Returns a manifest string representation of a proof. + * @param proofName - The name of the proof. + * @returns Manifest representation of the proof. + */ +export function manifestProof(proofName: string): string { + return `Proof("${proofName}")`; +} + +/** + * Returns a manifest string representation of a string. + * @param str - The string to represent. + * @returns Manifest representation of the string. + */ +export function manifestString(str: string): string { + return `"${str}"`; +} + +/** + * Returns a manifest string representation of a tuple. + * @param elements - The elements of the tuple. + * @returns Manifest representation of the tuple. + */ +export function manifestTuple(elements: string[]): string { + return `Tuple(${arrayToString(elements)})`; +} + +function arrayToString(elements: string[]): string { + return elements.join(", "); +} diff --git a/src/ManifestBuilder/StringManifestBuilder.ts b/src/ManifestBuilder/StringManifestBuilder.ts new file mode 100644 index 0000000..ea08a20 --- /dev/null +++ b/src/ManifestBuilder/StringManifestBuilder.ts @@ -0,0 +1,646 @@ +import { Decimal, Fungibles, NonFungibles } from "../Types/RadixTypes"; +import { + manifestAddress, + manifestAddressReservation, + manifestBucket, + manifestDecimal, + manifestLocalIdArray, + manifestMap, + manifestNamedAddress, + manifestProof, + manifestString, + manifestTuple, +} from "./ManifestTypes"; +import { convertToDataArray, convertToDataMap, instruction } from "./Utils"; + +export class StringManifestBuilder { + private _instructions: string[]; + + constructor() { + this._instructions = []; + } + + build(): string { + return this._instructions.join("\n"); + } + + lockFee(account: string, amount: Decimal): this { + return this.callMethod(account, "lock_fee", [manifestDecimal(amount)]); + } + + depositBatch(account: string): this { + return this.callMethod(account, "deposit_batch", [ + `Expression("ENTIRE_WORKTOP")`, + ]); + } + + nonFungibleBucket( + account: string, + bucket: NonFungibles, + bucketName: string, + ): this { + return this.callMethod(account, "withdraw_non_fungibles", [ + manifestAddress(bucket.address), + manifestLocalIdArray(bucket.ids), + ]).takeNonFungiblesFromWorktop(bucket.address, bucket.ids, bucketName); + } + + fungibleBucket(account: string, bucket: Fungibles, bucketName: string): this { + return this.callMethod(account, "withdraw", [ + manifestAddress(bucket.address), + manifestDecimal(bucket.amount), + ]).takeFromWorktop(bucket.address, bucket.amount, bucketName); + } + + proofOfAmount( + account: string, + resourceAddress: string, + amount: Decimal, + proofName: string, + ): this { + return this.callMethod(account, "create_proof_of_non_fungibles", [ + manifestAddress(resourceAddress), + manifestDecimal(amount), + ]).popFromAuthZone(proofName); + } + + nonFungibleProof( + account: string, + nonFungibles: NonFungibles, + proofName: string, + ): this { + return this.callMethod(account, "create_proof_of_amount", [ + manifestAddress(nonFungibles.address), + manifestLocalIdArray(nonFungibles.ids), + ]).popFromAuthZone(proofName); + } + + addRawInstruction(instruction: string): this { + this._instructions.push(instruction); + return this; + } + + /** + * Adds an instruction to allocate a global address. + * @param address - The global address. + * @param blueprintName - The name of the blueprint. + * @param reservationName - The reservation name. + * @param addressName - The named address. + * @returns The manifest instruction string for allocating the global address. + */ + allocateGlobalAddress( + address: string, + blueprintName: string, + reservationName: string, + addressName: string, + ): this { + this._instructions.push( + instruction("ALLOCATE_GLOBAL_ADDRESS", [ + manifestAddress(address), + manifestString(blueprintName), + manifestAddressReservation(reservationName), + manifestNamedAddress(addressName), + ]), + ); + return this; + } + + /** + * Adds an instruction to assert that the worktop contains a specified amount of a resource. + * @param address - The resource address. + * @param amount - The required amount. + * @returns The manifest instruction string for asserting the worktop contains the resource. + */ + assertWorktopContains(address: string, amount: Decimal): this { + this._instructions.push( + instruction("ASSERT_WORKTOP_CONTAINS", [ + manifestAddress(address), + manifestDecimal(amount), + ]), + ); + return this; + } + + /** + * Adds an instruction to assert that the worktop contains any amount of a resource. + * @param address - The resource address. + * @returns The manifest instruction string for asserting the worktop contains any of the resource. + */ + assertWorktopContainsAny(address: string): this { + this._instructions.push( + instruction("ASSERT_WORKTOP_CONTAINS", [manifestAddress(address)]), + ); + return this; + } + + /** + * Adds an instruction to assert that the worktop contains non-fungible tokens with specified IDs. + * @param address - The resource address. + * @param ids - The non-fungible IDs. + * @returns The manifest instruction string for asserting the worktop contains the specified non-fungible tokens. + */ + assertWorktopContainsNonFungibles(address: string, ids: string[]): this { + this._instructions.push( + instruction("ASSERT_WORKTOP_CONTAINS_NON_FUNGIBLES", [ + manifestAddress(address), + manifestLocalIdArray(ids), + ]), + ); + return this; + } + + /** + * Adds an instruction to burn a resource from a specified bucket. + * @param bucketName - The name of the bucket. + * @returns The manifest instruction string for burning the resource from the bucket. + */ + burnResource(bucketName: string): this { + this._instructions.push( + instruction("BURN_RESOURCE", [manifestBucket(bucketName)]), + ); + return this; + } + + /** + * Adds an instruction to call a function in a blueprint. + * @param packageAddress - The address of the package containing the blueprint. + * @param blueprintName - The name of the blueprint. + * @param functionName - The name of the function. + * @param args - The function arguments. + * @returns The manifest instruction string for calling the blueprint function. + */ + callFunction( + packageAddress: string, + blueprintName: string, + functionName: string, + args: string[], + ): this { + this._instructions.push( + instruction( + "CALL_FUNCTION", + [ + manifestAddress(packageAddress), + manifestString(blueprintName), + manifestString(functionName), + ].concat(args), + ), + ); + return this; + } + + /** + * Adds an instruction to call a method on a component. + * @param componentAddress - The address of the component. + * @param methodName - The name of the method. + * @param args - The method arguments. + * @returns The manifest instruction string for calling the component method. + */ + callMethod( + componentAddress: string, + methodName: string, + args: string[], + ): this { + this._instructions.push( + instruction( + "CALL_METHOD", + [manifestAddress(componentAddress), manifestString(methodName)].concat( + args, + ), + ), + ); + return this; + } + + /** + * Adds an instruction to claim royalties from a component. + * @param componentAddress - The address of the component. + * @returns The manifest instruction string for claiming component royalties. + */ + claimComponentRoyalties(componentAddress: string): this { + this._instructions.push( + instruction("CLAIM_COMPONENT_ROYALTIES", [ + manifestAddress(componentAddress), + ]), + ); + return this; + } + + /** + * Adds an instruction to claim royalties from a package. + * @param packageAddress - The address of the package. + * @returns The manifest instruction string for claiming package royalties. + */ + claimPackageRoyalties(packageAddress: string): this { + this._instructions.push( + instruction("CLAIM_PACKAGE_ROYALTIES", [manifestAddress(packageAddress)]), + ); + return this; + } + + /** + * Adds an instruction to clone a proof. + * @param originProofName - The original proof name. + * @param clonedProofName - The new cloned proof name. + * @returns The manifest instruction string for cloning the proof. + */ + cloneProof(originProofName: string, clonedProofName: string): this { + this._instructions.push( + instruction("CLONE_PROOF", [ + manifestProof(originProofName), + manifestProof(clonedProofName), + ]), + ); + return this; + } + + /** + * Adds an instruction to create an access controller. + * @param primaryRole - The primary role of the access controller. + * @param recoveryRole - The recovery role. + * @param confirmationRole - The confirmation role. + * @param timeRecoveryDelay - The optional time recovery delay. + * @param addressReservationName - The optional address reservation name. + * @returns The manifest instruction string for creating an access controller. + */ + createAccessController( + primaryRole: string, + recoveryRole: string, + confirmationRole: string, + timeRecoveryDelay?: number, + addressReservationName?: string, + ): this { + const args = [manifestTuple([primaryRole, recoveryRole, confirmationRole])]; + timeRecoveryDelay ? args.push(`Some(${timeRecoveryDelay}u64)`) : null; + addressReservationName + ? args.push(`Some(${manifestAddressReservation(addressReservationName)})`) + : null; + this._instructions.push(instruction("CREATE_ACCESS_CONTROLLER", args)); + return this; + } + + /** + * Adds an instruction to create a new account. + * @returns The manifest instruction string for creating an account. + */ + createAccount(): this { + this._instructions.push(instruction("CREATE_ACCOUNT", [])); + return this; + } + + /** + * Adds an instruction to create a new identity. + * @returns The manifest instruction string for creating an identity. + */ + createIdentity(): this { + this._instructions.push(instruction("CREATE_IDENTITY", [])); + return this; + } + + /** + * Adds an instruction to create a proof of all resources from the auth zone. + * @param resourceAddress - The resource address. + * @param proofName - The proof name. + * @returns The manifest instruction string for creating the proof. + */ + createProofFromAuthZoneOfAll( + resourceAddress: string, + proofName: string, + ): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_ALL", [ + manifestAddress(resourceAddress), + manifestProof(proofName), + ]), + ); + return this; + } + + /** + * Adds an instruction to create a proof of a specified amount of resources from the auth zone. + * @param resourceAddress - The resource address. + * @param amount - The amount of resources. + * @param proofName - The proof name. + * @returns The manifest instruction string for creating the proof of the specified amount. + */ + createProofFromAuthZoneOfAmount( + resourceAddress: string, + amount: Decimal, + proofName: string, + ): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_AMOUNT", [ + manifestAddress(resourceAddress), + manifestDecimal(amount), + manifestProof(proofName), + ]), + ); + return this; + } + + /** + * Adds an instruction to create a proof of non-fungible tokens from the auth zone. + * @param resourceAddress - The resource address. + * @param ids - The IDs of the non-fungible tokens. + * @param proofName - The proof name. + * @returns The manifest instruction string for creating the proof of non-fungible tokens. + */ + createProofFromAuthZoneOfNonFungibles( + resourceAddress: string, + ids: string[], + proofName: string, + ): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_NON_FUNGIBLES", [ + manifestAddress(resourceAddress), + manifestLocalIdArray(ids), + manifestProof(proofName), + ]), + ); + return this; + } + + createProofFromBucketOfAll(bucketName: string, proofName: string): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_ALL", [ + manifestBucket(bucketName), + manifestProof(proofName), + ]), + ); + return this; + } + + createProofFromBucketOfAmount( + bucketName: string, + amount: Decimal, + proofName: string, + ): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_ALL", [ + manifestBucket(bucketName), + manifestDecimal(amount), + manifestProof(proofName), + ]), + ); + return this; + } + + createProofFromBucketOfNonFungibles( + bucketName: string, + ids: string[], + proofName: string, + ): this { + this._instructions.push( + instruction("CREATE_PROOF_FROM_AUTH_ZONE_OF_ALL", [ + manifestBucket(bucketName), + manifestLocalIdArray(ids), + manifestProof(proofName), + ]), + ); + return this; + } + + /** + * Adds an instruction to drop all proofs from the auth zone. + * @returns The manifest instruction string for dropping all proofs. + */ + dropAllProofs(): this { + this._instructions.push(instruction("DROP_ALL_PROOFS", [])); + return this; + } + + /** + * Adds an instruction to drop all proofs from the auth zone. + * @returns The manifest instruction string for dropping all proofs from the auth zone. + */ + dropAuthZoneProofs(): this { + this._instructions.push(instruction("DROP_AUTH_ZONE_PROOFS", [])); + return this; + } + + dropAuthZoneRegularProofs(): this { + this._instructions.push(instruction("DROP_AUTH_ZONE_REGULAR_PROOFS", [])); + return this; + } + + dropAuthZoneSignatureProofs(): this { + this._instructions.push(instruction("DROP_AUTH_ZONE_SIGNATURE_PROOFS", [])); + return this; + } + + dropNamedProofs(): this { + this._instructions.push(instruction("DROP_NAMED_PROOFS", [])); + return this; + } + + lockComponentRoyalty(componentAddress: string, methodName: string): this { + this._instructions.push( + instruction("LOCK_COMPONENT_ROYALTY", [ + manifestAddress(componentAddress), + manifestString(methodName), + ]), + ); + return this; + } + + lockMetadata(entityAddress: string, fieldName: string): this { + this._instructions.push( + instruction("LOCK_METADATA", [ + manifestAddress(entityAddress), + manifestString(fieldName), + ]), + ); + return this; + } + + /** + * Adds an instruction to lock the owner role of an entity. + * @param entityAddress - The address of the entity. + * @returns The manifest instruction string for locking the owner role. + */ + lockOwnerRole(entityAddress: string): this { + this._instructions.push( + instruction("LOCK_OWNER_ROLE", [manifestAddress(entityAddress)]), + ); + return this; + } + + /** + * Adds an instruction to mint a specified amount of fungible tokens. + * @param resourceAddress - The resource address. + * @param amount - The amount of fungible tokens to mint. + * @returns The manifest instruction string for minting fungible tokens. + */ + mintFungible(resourceAddress: string, amount: Decimal): this { + this._instructions.push( + instruction("MINT_FUNGIBLE", [ + manifestAddress(resourceAddress), + manifestDecimal(amount), + ]), + ); + return this; + } + + /** + * Adds an instruction to mint non-fungible tokens. + * @param resourceAddress - The resource address. + * @param idDataMap - The map of non-fungible IDs to data. + * @returns The manifest instruction string for minting non-fungible tokens. + */ + mintNonFungible( + resourceAddress: string, + idDataMap: Map, + ): this { + this._instructions.push( + instruction("MINT_NON_FUNGIBLE", [ + manifestAddress(resourceAddress), + manifestMap("NonFungibleLocalId", "Tuple", convertToDataMap(idDataMap)), + ]), + ); + return this; + } + + /** + * Adds an instruction to mint RUID non-fungible tokens. + * @param resourceAddress - The resource address. + * @param dataArray - The array of non-fungible data. + * @returns The manifest instruction string for minting non-fungible tokens. + */ + mintRuidNonFungible(resourceAddress: string, dataArray: string[][]): this { + this._instructions.push( + instruction("MINT_RUID_NON_FUNGIBLE", [ + manifestAddress(resourceAddress), + convertToDataArray(dataArray), + ]), + ); + return this; + } + + popFromAuthZone(proofName: string): this { + this._instructions.push( + instruction("POP_FROM_AUTH_ZONE", [manifestProof(proofName)]), + ); + return this; + } + + pushToAuthZone(proofName: string): this { + this._instructions.push( + instruction("PUSH_TO_AUTH_ZONE", [manifestProof(proofName)]), + ); + return this; + } + + /** + * Adds an instruction to recall a specified amount of resources from a vault. + * @param vaultAddress - The vault address. + * @param amount - The amount to recall. + * @returns The manifest instruction string for recalling resources from the vault. + */ + recall(vaultAddress: string, amount: Decimal): this { + this._instructions.push( + instruction("RECALL_FROM_VAULT", [ + manifestAddress(vaultAddress), + manifestDecimal(amount), + ]), + ); + return this; + } + + recallNonFungibles(vaultAddress: string, ids: string[]): this { + this._instructions.push( + instruction("RECALL_NON_FUNGIBLES_FROM_VAULT", [ + manifestAddress(vaultAddress), + manifestLocalIdArray(ids), + ]), + ); + return this; + } + + removeMetadata(resourceAddress: string, fieldName: string): this { + this._instructions.push( + instruction("REMOVE_METADATA", [ + manifestAddress(resourceAddress), + manifestString(fieldName), + ]), + ); + return this; + } + + /** + * Adds an instruction to return resources to the worktop. + * @param bucketName - The name of the bucket. + * @returns The manifest instruction string for returning resources to the worktop. + */ + returnToWorktop(bucketName: string): this { + this._instructions.push( + instruction("RETURN_TO_WORKTOP", [manifestBucket(bucketName)]), + ); + return this; + } + + setComponentRoyalty( + componentAddress: string, + methodName: string, + amount: Decimal, + ) { + const royaltyArg = + amount.toString() == "0" + ? `Enum()` + : "Enum(${amount})"; + + this._instructions.push( + instruction("SET_COMPONENT_ROYALTY", [ + manifestAddress(componentAddress), + manifestString(methodName), + royaltyArg, + ]), + ); + return this; + } + + takeAllFromWorktop(resourceAddress: string, bucketName: string): this { + this._instructions.push( + instruction("TAKE_ALL_FROM_WORKTOP", [ + manifestAddress(resourceAddress), + manifestBucket(bucketName), + ]), + ); + return this; + } + + /** + * Adds an instruction to take a specified amount of fungible tokens from the worktop. + * @param resourceAddress - The resource address. + * @param amount - The amount to take. + * @param bucketName - The name of the bucket to store the tokens. + * @returns The manifest instruction string for taking tokens from the worktop. + */ + takeFromWorktop( + resourceAddress: string, + amount: Decimal, + bucketName: string, + ): this { + this._instructions.push( + instruction("TAKE_FROM_WORKTOP", [ + manifestAddress(resourceAddress), + manifestDecimal(amount), + manifestBucket(bucketName), + ]), + ); + return this; + } + + takeNonFungiblesFromWorktop( + resourceAddress: string, + ids: string[], + bucketName: string, + ): this { + this._instructions.push( + instruction("TAKE_NON_FUNGIBLES_FROM_WORKTOP", [ + manifestAddress(resourceAddress), + manifestLocalIdArray(ids), + manifestBucket(bucketName), + ]), + ); + return this; + } +} diff --git a/src/ManifestBuilder/Utils.ts b/src/ManifestBuilder/Utils.ts new file mode 100644 index 0000000..7286ed3 --- /dev/null +++ b/src/ManifestBuilder/Utils.ts @@ -0,0 +1,32 @@ +import { manifestArray, manifestLocalId, manifestTuple } from "./ManifestTypes"; + +export function instruction( + instructionName: string, + instructionArguments: string[], +): string { + return `${instructionName}\n\t${argumentsString(instructionArguments)}\n;`; +} + +export function argumentsString(args: string[]): string { + return args.join("\n\t"); +} + +export function convertToDataMap( + idDataMap: Map, +): Map { + const correctedMap = new Map(); + for (const [key, value] of idDataMap.entries()) { + correctedMap.set( + manifestLocalId(key), + manifestTuple([manifestTuple(value)]), + ); + } + return correctedMap; +} + +export function convertToDataArray(dataArray: string[][]): string { + const elements = dataArray.map((elems) => + manifestTuple([manifestTuple(elems)]), + ); + return manifestArray("Tuple", elements); +} diff --git a/src/StringManifest/MethodsHelper.ts b/src/StringManifest/MethodsHelper.ts deleted file mode 100644 index abbebba..0000000 --- a/src/StringManifest/MethodsHelper.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { - AccountAddress, - ComponentAddress, - Decimal, - FungibleBucket, - NFT, - NonFungibleBucket, - ResourceAddress, -} from "../Types/RadixTypes"; - -/** - * Returns a manifest address. - * @param globalAddress Address of the component/account/resource. - */ -export function addressFrom(globalAddress: string): string { - return `Address("${globalAddress}")`; -} - -/** - * Returns a manifest lock fee instruction. - * @param account Account that will pay for the fee. - * @param amount Amount of fees to lock. - */ -export function lockFee(account: string, amount?: Decimal): string { - let to_lock = amount ? amount : 20; - return callMethod("lock_fee", account, [decimalToArg(to_lock)]); -} - -/** - * Returns a manifest instruction to create a fungible bucket. - * @param account Account from which to withdraw the tokens. - * @param bucket Fungible bucket to create. - * @param bucketName Name of the fungible bucket. - */ -export function fungibleBucket( - account: AccountAddress, - bucket: FungibleBucket, - bucketName: string, -): string { - return ` - CALL_METHOD - ${addressFrom(account)} - "withdraw" - ${addressFrom(bucket.address)} - ${decimalToArg(bucket.amount)}; - - TAKE_FROM_WORKTOP - ${addressFrom(bucket.address)} - ${decimalToArg(bucket.amount)} - Bucket("${bucketName}");`; -} - -/** - * Returns a manifest instruction to create a non-fungible bucket. - * @param account Account from which to withdraw the non-fungible tokens. - * @param bucket Non-fungible bucket to create. - * @param bucketName Name of the non-fungible bucket. - */ -export function nonFungibleBucket( - account: AccountAddress, - bucket: NonFungibleBucket, - bucketName: string, -): string { - const ids_string = bucket.ids.map((id) => { - return `NonFungibleLocalId("${id}")`; - }); - - const ids_vec = array("NonFungibleLocalId", ids_string); - - let withdraw_call = callMethod("withdraw_non_fungibles", account, [ - `Address("${bucket.address}")`, - ids_vec, - ]); - - let take_call = ` - TAKE_NON_FUNGIBLES_FROM_WORKTOP - ${addressFrom(bucket.address)} - ${ids_vec} - Bucket("${bucketName}"); - `; - - return ` - ${withdraw_call} - - ${take_call}`; -} - -/** - * Returns a manifest instruction to create a proof of a non-fungible token. - * @param account Account where the NFT belongs. - * @param proof Proof to create. - * @param proof_name Name of the proof. - */ -export function proofToArg( - account: AccountAddress, - proof: NFT, - proof_name: string, -): string { - return ` - CALL_METHOD - ${addressFrom(account)} - "create_proof_of_non_fungibles" - ${addressFrom(proof.address)} - Array(NonFungibleLocalId("${proof.id}")); - - CREATE_PROOF_FROM_AUTH_ZONE_OF_NON_FUNGIBLES - ${addressFrom(proof.address)} - Array(NonFungibleLocalId("${proof.id}")) - Proof("${proof_name}");`; -} - -/** - * Returns a manifest array. - * @param type_name Type of the items of the array. - * @param content Content of the array. - */ -export function array(type_name: string, content: T[]): string { - let vec_string = `Array<${type_name}>(`; - content.forEach((item) => { - vec_string += `${item}, `; - }); - if(content.length > 0){ - vec_string= vec_string.slice(0, -2) - } - vec_string += ")" - - return vec_string; -} - -export function decimalToArg(decimal: Decimal): string { - return `Decimal("${decimal}")` -} - -/** - * Returns a manifest instruction to create a proof of an amount of fungibles. - * @param account Account from which to create the proof. - * @param resourceAddress Resource address of the proof. - * @param amount Amount of fungibles in the proof. - */ -export function createProofOfAmount( - account: AccountAddress, - resourceAddress: ResourceAddress, - amount: Decimal, -): string { - return callMethod("create_proof_of_amount", account, [ - addressFrom(resourceAddress), - decimalToArg(amount), - ]); -} - -/** - * Returns a manifest instruction to deposit all resources on the worktop to a given account. - * @param account Account where to deposit the resources. - */ -export function depositBatch(account: AccountAddress): string { - return callMethod("deposit_batch", account, [`Expression("ENTIRE_WORKTOP")`]); -} - -/** - * Returns a manifest instruction to call a given method. - * @param methodName Name of the method. - * @param componentAddress Address of the method's component. - * @param args Manifest version of the method's arguments. - */ -export function callMethod( - methodName: string, - componentAddress: ComponentAddress, - args: string[], -): string { - let partial_return = ` - CALL_METHOD - Address("${componentAddress}") - "${methodName}"`; - - args.forEach((arg) => { - partial_return += ` - ${arg}`; - }); - - partial_return += ";"; - return partial_return; -} diff --git a/src/Types/NFT.ts b/src/Types/NFT.ts new file mode 100644 index 0000000..f2630a7 --- /dev/null +++ b/src/Types/NFT.ts @@ -0,0 +1,41 @@ +export class NFT { + private readonly _resourceAddress: string; + private readonly _localId: string; + + constructor(resourceAddress: string, localId: string) { + this._resourceAddress = resourceAddress; + this._localId = localId; + } + + public static fromGlobalId(globalId: string) { + const parts = globalId.split(":"); + const resourceAddress = parts[0]; + const localId = parts[1]; + if (resourceAddress !== null && localId !== null) { + return new NFT(resourceAddress, localId); + } else { + throw new Error("The Global Id input doesn't have the right format!"); + } + } + + address(): string { + return this._resourceAddress; + } + + localId(): string { + return this._localId; + } + + globalId(): string { + return this._resourceAddress + ":" + this._localId; + } + + toString(): string { + new Map(); + return this.globalId(); + } + + equals(other: NFT): boolean { + return this.globalId() === other.globalId(); + } +} diff --git a/src/Types/RadixTypes.ts b/src/Types/RadixTypes.ts index dc6d9f3..82f9a49 100644 --- a/src/Types/RadixTypes.ts +++ b/src/Types/RadixTypes.ts @@ -1,28 +1,16 @@ import BigNumber from "bignumber.js"; import { EntityMetadataItemValue } from "@radixdlt/babylon-gateway-api-sdk"; -export type AccountAddress = string; -export type ComponentAddress = string; -export type NonFungibleGlobalId = string; -export type NonFungibleLocalId = string; -export type PackageAddress = string; -export type ResourceAddress = string; - export type Decimal = number | string | BigNumber; -export type FungibleBucket = { - address: ResourceAddress; +export type Fungibles = { + address: string; amount: Decimal; }; -export type NonFungibleBucket = { - address: ResourceAddress; - ids: NonFungibleLocalId[]; -}; - -export type NFT = { - address: NonFungibleGlobalId; - id: NonFungibleLocalId; +export type NonFungibles = { + address: string; + ids: string[]; }; export type NonFungibleData = { diff --git a/src/index.ts b/src/index.ts index feae587..236aa3e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ -export * from './GatewayProcessor/GatewayProcessor' -export * from './StringManifest/MethodsHelper' -export * from './Types/RadixTypes' +export * from "./GatewayProcessor/GatewayProcessor"; +export * from "./ManifestBuilder/StringManifestBuilder"; +export * from "./ManifestBuilder/ManifestTypes"; +export * from "./Types/RadixTypes"; diff --git a/tests/GatewayProcessor.tests.ts b/tests/GatewayProcessor.tests.ts index 5f0d350..67537bd 100644 --- a/tests/GatewayProcessor.tests.ts +++ b/tests/GatewayProcessor.tests.ts @@ -1,14 +1,12 @@ -import { GatewayProcessor } from "../src"; -import { NetworkId } from "@radixdlt/radix-engine-toolkit"; import { - ComponentAddress, - FungibleResource, - NonFungibleItem, - NonFungibleResource, - ResourceAddress, + GatewayProcessor, + manifestBucket, + StringManifestBuilder, } from "../src"; +import { NetworkId } from "@radixdlt/radix-engine-toolkit"; +import { FungibleResource, NonFungibleItem, NonFungibleResource } from "../src"; -const toolkit_test_account: ComponentAddress = +const toolkit_test_account: string = "account_tdx_2_12xckkd70cgwp6a8k2td9d9r0kch7h3dl47ghpvwkdcl7uj7wyw99ca"; test("Test Parse Resource Information", async () => { @@ -77,7 +75,7 @@ test("Test Get Fungible Resources", async () => { expect(fungibles_held.length).toEqual(2); - let resource_map = new Map(); + let resource_map = new Map(); fungibles_held.forEach((resource) => { resource_map.set(resource.address, resource); }); @@ -107,7 +105,7 @@ test("Test Get Non Fungible Resources", async () => { expect(non_fungibles_held.length).toEqual(2); - let resource_map = new Map(); + let resource_map = new Map(); non_fungibles_held.forEach((resource) => { resource_map.set(resource.address, resource); }); @@ -224,3 +222,43 @@ test("Test get data with state", async () => { expect(item.name).toBeDefined(); expect(item.image_url).toBeDefined(); }); + +test("Manifest builder ", () => { + const account = + "account_tdx_2_12yx3ftggkd62d5hew8pfkm9tfffenyj5zy4gvd2hdemqck64ywsvx4"; + const component = + "component_tdx_2_1crttvh8h9y9f23r73s89vr78gtsv4qm0k6t3eg8vlj6jre0x7ykx88"; + const xrd = + "resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc"; + + const manifest = new StringManifestBuilder() + .fungibleBucket(account, { address: xrd, amount: 120 }, "bucket") + .callMethod(component, "bid", ["1u64", manifestBucket("bucket")]) + .depositBatch(account) + .build(); + + expect(manifest).toEqual( + `CALL_METHOD +\tAddress("account_tdx_2_12yx3ftggkd62d5hew8pfkm9tfffenyj5zy4gvd2hdemqck64ywsvx4") +\t"withdraw" +\tAddress("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") +\tDecimal("120") +; +TAKE_FROM_WORKTOP +\tAddress("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") +\tDecimal("120") +\tBucket("bucket") +; +CALL_METHOD +\tAddress("component_tdx_2_1crttvh8h9y9f23r73s89vr78gtsv4qm0k6t3eg8vlj6jre0x7ykx88") +\t"bid" +\t1u64 +\tBucket("bucket") +; +CALL_METHOD +\tAddress("account_tdx_2_12yx3ftggkd62d5hew8pfkm9tfffenyj5zy4gvd2hdemqck64ywsvx4") +\t"deposit_batch" +\tExpression("ENTIRE_WORKTOP") +;`, + ); +});