From 6ed95e3cf63d2911668445c98cb7df0ba7d3081b Mon Sep 17 00:00:00 2001 From: Damjan Dimitrov Date: Tue, 10 Dec 2024 08:53:58 +0100 Subject: [PATCH 1/3] Local version updates --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fe4c45..e1d2943 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7990,7 +7990,7 @@ }, "packages/cli": { "name": "@apillon/cli", - "version": "1.5.0", + "version": "1.6.0", "license": "MIT", "dependencies": { "@apillon/sdk": "*", @@ -8029,7 +8029,7 @@ }, "packages/sdk": { "name": "@apillon/sdk", - "version": "3.6.0", + "version": "3.7.0", "license": "MIT", "dependencies": { "@polkadot/util-crypto": "^12.6.2", From 8a11e0e41ca0d618a3fa5f322840951ee3860232 Mon Sep 17 00:00:00 2001 From: Damjan Dimitrov Date: Tue, 17 Dec 2024 13:40:10 +0100 Subject: [PATCH 2/3] Add support for Unique NFTs --- package-lock.json | 2 +- packages/sdk/package.json | 2 +- packages/sdk/src/modules/nft/nft.ts | 18 ++++++-- packages/sdk/src/tests/nft.test.ts | 43 +++++++++++++++++++ packages/sdk/src/types/nfts.ts | 66 +++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e1d2943..217d888 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8029,7 +8029,7 @@ }, "packages/sdk": { "name": "@apillon/sdk", - "version": "3.7.0", + "version": "3.8.0", "license": "MIT", "dependencies": { "@polkadot/util-crypto": "^12.6.2", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 421aa48..5c1f6f4 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,7 +1,7 @@ { "name": "@apillon/sdk", "description": "▶◀ Apillon SDK for NodeJS ▶◀", - "version": "3.7.0", + "version": "3.8.0", "author": "Apillon", "license": "MIT", "main": "./dist/index.js", diff --git a/packages/sdk/src/modules/nft/nft.ts b/packages/sdk/src/modules/nft/nft.ts index 768890a..5a9448c 100644 --- a/packages/sdk/src/modules/nft/nft.ts +++ b/packages/sdk/src/modules/nft/nft.ts @@ -7,6 +7,7 @@ import { ICreateCollection, ICreateSubstrateCollection, ICreateCollectionBase, + ICreateUniqueCollection, } from '../../types/nfts'; import { NftCollection } from './nft-collection'; @@ -52,7 +53,7 @@ export class Nft extends ApillonModule { * @returns A NftCollection instance. */ public async create(data: ICreateCollection) { - return await this.createNft(data, true); + return await this.createNft(data, 'evm'); } /** @@ -61,17 +62,26 @@ export class Nft extends ApillonModule { * @returns A NftCollection instance. */ public async createSubstrate(data: ICreateSubstrateCollection) { - return await this.createNft(data, false); + return await this.createNft(data, 'substrate'); } - private async createNft(data: ICreateCollectionBase, isEvm: boolean) { + /** + * Deploys a new Unique NftCollection smart contract. + * @param data NFT collection data. + * @returns A NftCollection instance. + */ + public async createUnique(data: ICreateUniqueCollection) { + return await this.createNft(data, 'unique'); + } + + private async createNft(data: ICreateCollectionBase, type: string) { // If not drop, set drop properties to default 0 if (!data.drop) { data.dropStart = data.dropPrice = data.dropReserve = 0; } const response = await ApillonApi.post< NftCollection & { collectionUuid: string } - >(`${this.API_PREFIX}/${isEvm ? 'evm' : 'substrate'}`, data); + >(`${this.API_PREFIX}/${type}`, data); return new NftCollection(response.collectionUuid, response); } } diff --git a/packages/sdk/src/tests/nft.test.ts b/packages/sdk/src/tests/nft.test.ts index 1c9c10b..008497f 100644 --- a/packages/sdk/src/tests/nft.test.ts +++ b/packages/sdk/src/tests/nft.test.ts @@ -67,6 +67,49 @@ describe('Nft tests', () => { expect(collection.isSoulbound).toEqual(false); }); + test.only('creates a new unique collection', async () => { + const uniqueCollectionData = { + ...nftData, + maxSupply: 1000, + isRevokable: true, + isSoulbound: false, + metadata: { + '1': { + name: 'Unique NFT 1', + description: 'Description for Unique NFT 1', + image: 'https://example.com/nft1.png', + attributes: { + value: 'Attribute Value 1', + trait_type: 'Attribute Type 1', + display_type: 'string', + }, + }, + '2': { + name: 'Unique NFT 2', + description: 'Description for Unique NFT 2', + image: 'https://example.com/nft2.png', + attributes: { + value: 'Attribute Value 2', + trait_type: 'Attribute Type 2', + display_type: 'string', + }, + }, + }, + }; + + const collection = await nft.createUnique(uniqueCollectionData); + expect(collection.uuid).toBeDefined(); + expect(collection.contractAddress).toBeDefined(); + expect(collection.symbol).toEqual('SDKT'); + expect(collection.name).toEqual('SDK Test'); + expect(collection.description).toEqual('Created from SDK tests'); + expect(collection.isAutoIncrement).toEqual(true); + expect(collection.isRevokable).toEqual(true); + expect(collection.isSoulbound).toEqual(false); + + collectionUuid = collection.uuid; + }); + test('mints a new nft', async () => { const collection = nft.collection(collectionUuid); const res = await collection.mint({ diff --git a/packages/sdk/src/types/nfts.ts b/packages/sdk/src/types/nfts.ts index c01b248..7860666 100644 --- a/packages/sdk/src/types/nfts.ts +++ b/packages/sdk/src/types/nfts.ts @@ -8,6 +8,7 @@ export enum EvmChain { export enum SubstrateChain { ASTAR = 8, + UNIQUE = 11, } export enum CollectionStatus { @@ -57,9 +58,21 @@ export interface ICreateCollectionBase { } export interface ICreateCollection extends ICreateCollectionBase { + /** + * Indicates if the collection is revokable (burnable). + */ isRevokable: boolean; + /** + * Indicates if the collection is soulbound. + */ isSoulbound: boolean; + /** + * If enabled, newly minted NFTs will have token IDs in sequential order. + */ isAutoIncrement?: boolean; + /** + * The EVM chain on which the collection will be deployed. + */ chain: EvmChain; } @@ -67,6 +80,59 @@ export interface ICreateSubstrateCollection extends ICreateCollectionBase { chain: SubstrateChain; } +export interface IMetadataAttributes { + /** + * Trait value. + */ + value: string; + /** + * Name of the trait. + */ + trait_type: string; + /** + * Type for displaying trait (number, date,...). + */ + display_type: string; +} + +export interface IMetadata { + /** + * NFT name. + */ + name: string; + /** + * NFT description. + */ + description: string; + /** + * NFT image URL. + */ + image: string; + /** + * Array of NFT attributes. + */ + attributes: IMetadataAttributes; +} + +export interface ICreateUniqueCollection extends ICreateCollectionBase { + /** + * Maximum supply of the collection. + */ + maxSupply: number; + /** + * For revokable collection owner can destroy (burn) NFTs at any time. + */ + isRevokable: boolean; + /** + * Soulbound tokens are NFTs that are bound to wallet and not transferable. (default: false) + */ + isSoulbound: boolean; + /** + * Object containing metadata for different token ids. + */ + metadata: { [tokenId: string]: IMetadata }; +} + export interface ITransaction { chainId: number; transactionType: TransactionType; From 4cea1418212e05eae55b096a399f5c92a3e9d295 Mon Sep 17 00:00:00 2001 From: Damjan Dimitrov Date: Tue, 17 Dec 2024 13:44:11 +0100 Subject: [PATCH 3/3] Add unique collection example --- packages/sdk/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/sdk/README.md b/packages/sdk/README.md index cf9a34c..9df913d 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -277,6 +277,39 @@ const substrateCollection = await nft.createSubstrate({ ... }); +// or create a unique collection +const uniqueCollection = await nft.createUnique({ + collectionType: CollectionType.GENERIC, + chain: SubstrateChain.UNIQUE, + name: 'UniqueArtworks', + symbol: 'UA', + description: 'A collection of one-of-a-kind digital artworks.', + isRevokable: false, + isSoulbound: false, + metadata: { + '1': { + name: 'Unique NFT 1', + description: 'Description for Unique NFT 1', + image: 'https://example.com/nft1.png', + attributes: { + trait_type: 'color', + value: 'red', + display_type: 'string', + }, + }, + '2': { + name: 'Unique NFT 2', + description: 'Description for Unique NFT 2', + image: 'https://example.com/nft2.png', + attributes: { + trait_type: 'color', + value: 'blue', + display_type: 'string', + }, + }, + }, +}); + // check if collection is deployed - available on chain if (collection.collectionStatus == CollectionStatus.DEPLOYED) { console.log('Collection deployed: ', collection.transactionHash);