diff --git a/src/api/collection.ts b/src/api/collection.ts index 94ba639fa..477c7cef4 100644 --- a/src/api/collection.ts +++ b/src/api/collection.ts @@ -2,7 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import { AptosConfig } from "./aptosConfig"; -import { getCollectionId, getCollectionData } from "../internal/collection"; +import { + CreateCollectionOptions, + createCollectionTransaction, + getCollectionId, + getCollectionData, +} from "../internal/collection"; +import { Account } from "../core"; +import { GenerateTransactionOptions, SingleSignerTransaction } from "../transactions/types"; import { GetCollectionDataResponse, HexInput, TokenStandard } from "../types"; /** @@ -15,6 +22,43 @@ export class Collection { this.config = config; } + /** + * Creates a new collection within the specified account + * + * @param args.creator the account of the collection's creator + * @param args.description the description of the collection + * @param args.name the name of the collection + * @param args.uri the URI to additional info about the collection + * + * The parameters below are optional. + * @param args.maxSupply controls the max supply of the tokens - defaults MAX_U64_BIG_INT + * @param args.mutableDescription controls mutability of the collection's description - defaults true + * @param args.mutableRoyalty controls mutability of the collection's description - defaults true + * @param args.mutableUri controls mutability of the collection's URI - defaults true + * @param args.mutableTokenDescription controls mutability of the token's description - defaults true + * @param args.mutableTokenName controls mutability of the token's name - defaults true + * @param args.mutableTokenProperties controls mutability of token's properties - defaults true + * @param args.mutableTokenUri controls mutability of the token's URI - defaults true + * @param args.tokensBurnableByCreator controls whether tokens can be burnable by the creator - defaults true + * @param args.tokensFreezableByCreator controls whether tokens can be frozen by the creator - defaults true + * @param args.royaltyNumerator the numerator of the royalty to be paid to the creator when a token is transferred - defaults 0 + * @param args.royaltyDenominator the denominator of the royalty to be paid to the creator when a token is transferred - + * defaults 1 + * + * @returns A SingleSignerTransaction that when submitted will create the collection. + */ + async createCollectionTransaction( + args: { + creator: Account; + description: string; + name: string; + uri: string; + options?: GenerateTransactionOptions; + } & CreateCollectionOptions, + ): Promise { + return createCollectionTransaction({ aptosConfig: this.config, ...args }); + } + /** * Queries data of a specific collection by the collection creator address and the collection name. * diff --git a/src/internal/collection.ts b/src/internal/collection.ts index feb0691f3..07d9f049c 100644 --- a/src/internal/collection.ts +++ b/src/internal/collection.ts @@ -9,11 +9,71 @@ */ import { AptosConfig } from "../api/aptosConfig"; -import { Hex } from "../core"; -import { GetCollectionDataResponse, HexInput, TokenStandard } from "../types"; +import { Bool, U64 } from "../bcs/serializable/movePrimitives"; +import { Account, Hex } from "../core"; +import { GenerateTransactionOptions, SingleSignerTransaction } from "../transactions/types"; +import { AnyNumber, GetCollectionDataResponse, HexInput, TokenStandard } from "../types"; import { GetCollectionDataQuery } from "../types/generated/operations"; import { GetCollectionData } from "../types/generated/queries"; import { queryIndexer } from "./general"; +import { generateTransaction } from "./transactionSubmission"; +import { MoveString } from "../bcs/serializable/moveStructs"; +import { MAX_U64_BIG_INT } from "../bcs/consts"; + +export interface CreateCollectionOptions { + maxSupply?: AnyNumber; + mutableDescription?: boolean; + mutableRoyalty?: boolean; + mutableURI?: boolean; + mutableTokenDescription?: boolean; + mutableTokenName?: boolean; + mutableTokenProperties?: boolean; + mutableTokenURI?: boolean; + tokensBurnableByCreator?: boolean; + tokensFreezableByCreator?: boolean; + royaltyNumerator?: number; + royaltyDenominator?: number; +} + +export async function createCollectionTransaction( + args: { + aptosConfig: AptosConfig; + creator: Account; + description: string; + name: string; + uri: string; + options?: GenerateTransactionOptions; + } & CreateCollectionOptions, +): Promise { + const { aptosConfig, options, creator } = args; + const transaction = await generateTransaction({ + aptosConfig, + sender: creator.accountAddress.toString(), + data: { + function: "0x4::aptos_token::create_collection", + arguments: [ + // Do not change the order + new MoveString(args.description), + new U64(args.maxSupply ?? MAX_U64_BIG_INT), + new MoveString(args.name), + new MoveString(args.uri), + new Bool(args.mutableDescription ?? true), + new Bool(args.mutableRoyalty ?? true), + new Bool(args.mutableURI ?? true), + new Bool(args.mutableTokenDescription ?? true), + new Bool(args.mutableTokenName ?? true), + new Bool(args.mutableTokenProperties ?? true), + new Bool(args.mutableTokenURI ?? true), + new Bool(args.tokensBurnableByCreator ?? true), + new Bool(args.tokensFreezableByCreator ?? true), + new U64(args.royaltyNumerator ?? 0), + new U64(args.royaltyDenominator ?? 1), + ], + }, + options, + }); + return transaction as SingleSignerTransaction; +} /** * Queries data of a specific collection by the collection creator address and the collection name. diff --git a/tests/e2e/api/collection.test.ts b/tests/e2e/api/collection.test.ts index a175248b4..d31f28516 100644 --- a/tests/e2e/api/collection.test.ts +++ b/tests/e2e/api/collection.test.ts @@ -1,44 +1,54 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -// import { Aptos, AptosConfig, Network } from "../../../src"; +import { Account, Aptos, AptosConfig, Network } from "../../../src"; +import { waitForTransaction } from "../../../src/internal/transaction"; +import { FUND_AMOUNT } from "../../unit/helper"; + +// use it here since all tests use the same configuration +const config = new AptosConfig({ network: Network.LOCAL }); +const aptos = new Aptos(config); // Disable these tests for now until we can test against LOCAL describe("Collection", () => { - test("it should get collection data", async () => { - /* - const config = new AptosConfig({ network: Network.MAINNET }); - const aptos = new Aptos(config); + test("it creates a new collection on chain and fetches its data", async () => { + const creator = Account.generate(); + const creatorAddress = creator.accountAddress.toString(); + const collectionName = "Aptos Test NFT Collection"; + const collectionDescription = "My new collection!"; + const collectionUri = "http://aptos.dev"; + + await aptos.fundAccount({ accountAddress: creatorAddress, amount: FUND_AMOUNT }); + + const transaction = await aptos.createCollectionTransaction({ + creator, + description: collectionDescription, + name: collectionName, + uri: collectionUri, + }); + const response = await aptos.signAndSubmitTransaction({ signer: creator, transaction }); + + await waitForTransaction({ aptosConfig: config, transactionHash: response.hash }); - const collectionName = "BoredApePixels"; - const creatorAddress = "0x3d5886363f0a09578b71361ccc86a65310ff2782a0ec18f9a250c9bb0ac46ac5"; const data = await aptos.getCollectionData({ collectionName, creatorAddress }); + + expect(data.collection_name).toEqual(collectionName); + expect(data.creator_address).toEqual(creatorAddress); + expect(data.description).toEqual(collectionDescription); + expect(data.uri).toEqual(collectionUri); + expect(data.current_supply).toEqual(0); + expect(data.mutable_description).toEqual(true); + expect(data.mutable_uri).toEqual(true); + expect(data.token_standard).toEqual("v2"); + + expect(data).toHaveProperty("max_supply"); expect(data).toHaveProperty("collection_id"); - expect(data).toHaveProperty("collection_name"); - expect(data).toHaveProperty("creator_address"); - expect(data).toHaveProperty("current_supply"); - expect(data).toHaveProperty("description"); expect(data).toHaveProperty("last_transaction_timestamp"); expect(data).toHaveProperty("last_transaction_version"); - expect(data).toHaveProperty("max_supply"); - expect(data).toHaveProperty("mutable_description"); - expect(data).toHaveProperty("mutable_uri"); expect(data).toHaveProperty("table_handle_v1"); - expect(data).toHaveProperty("token_standard"); expect(data).toHaveProperty("total_minted_v2"); - expect(data).toHaveProperty("uri"); - */ - }); - - test("it should get a collection's address", async () => { - /* - const config = new AptosConfig({ network: Network.MAINNET }); - const aptos = new Aptos(config); - const collectionName = "BoredApePixels"; - const creatorAddress = "0x3d5886363f0a09578b71361ccc86a65310ff2782a0ec18f9a250c9bb0ac46ac5"; - const address = await aptos.getCollectionAddress({ collectionName, creatorAddress }); - expect(address).toEqual("0x5e298466bb613f881f3157ddafe2ce217d207fd634048242bff642d4bcd67503"); - */ + const address = await aptos.getCollectionId({ collectionName, creatorAddress }); + expect(address).toEqual(data.collection_id); }); });