Skip to content

Commit de4b8cb

Browse files
authored
Merge pull request #41 from dimitrov-d/master
Add support for Unique NFTs
2 parents 5a5de86 + 4cea141 commit de4b8cb

File tree

6 files changed

+159
-7
lines changed

6 files changed

+159
-7
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/sdk/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,39 @@ const substrateCollection = await nft.createSubstrate({
277277
...
278278
});
279279

280+
// or create a unique collection
281+
const uniqueCollection = await nft.createUnique({
282+
collectionType: CollectionType.GENERIC,
283+
chain: SubstrateChain.UNIQUE,
284+
name: 'UniqueArtworks',
285+
symbol: 'UA',
286+
description: 'A collection of one-of-a-kind digital artworks.',
287+
isRevokable: false,
288+
isSoulbound: false,
289+
metadata: {
290+
'1': {
291+
name: 'Unique NFT 1',
292+
description: 'Description for Unique NFT 1',
293+
image: 'https://example.com/nft1.png',
294+
attributes: {
295+
trait_type: 'color',
296+
value: 'red',
297+
display_type: 'string',
298+
},
299+
},
300+
'2': {
301+
name: 'Unique NFT 2',
302+
description: 'Description for Unique NFT 2',
303+
image: 'https://example.com/nft2.png',
304+
attributes: {
305+
trait_type: 'color',
306+
value: 'blue',
307+
display_type: 'string',
308+
},
309+
},
310+
},
311+
});
312+
280313
// check if collection is deployed - available on chain
281314
if (collection.collectionStatus == CollectionStatus.DEPLOYED) {
282315
console.log('Collection deployed: ', collection.transactionHash);

packages/sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@apillon/sdk",
33
"description": "▶◀ Apillon SDK for NodeJS ▶◀",
4-
"version": "3.7.0",
4+
"version": "3.8.0",
55
"author": "Apillon",
66
"license": "MIT",
77
"main": "./dist/index.js",

packages/sdk/src/modules/nft/nft.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ICreateCollection,
88
ICreateSubstrateCollection,
99
ICreateCollectionBase,
10+
ICreateUniqueCollection,
1011
} from '../../types/nfts';
1112
import { NftCollection } from './nft-collection';
1213

@@ -52,7 +53,7 @@ export class Nft extends ApillonModule {
5253
* @returns A NftCollection instance.
5354
*/
5455
public async create(data: ICreateCollection) {
55-
return await this.createNft(data, true);
56+
return await this.createNft(data, 'evm');
5657
}
5758

5859
/**
@@ -61,17 +62,26 @@ export class Nft extends ApillonModule {
6162
* @returns A NftCollection instance.
6263
*/
6364
public async createSubstrate(data: ICreateSubstrateCollection) {
64-
return await this.createNft(data, false);
65+
return await this.createNft(data, 'substrate');
6566
}
6667

67-
private async createNft(data: ICreateCollectionBase, isEvm: boolean) {
68+
/**
69+
* Deploys a new Unique NftCollection smart contract.
70+
* @param data NFT collection data.
71+
* @returns A NftCollection instance.
72+
*/
73+
public async createUnique(data: ICreateUniqueCollection) {
74+
return await this.createNft(data, 'unique');
75+
}
76+
77+
private async createNft(data: ICreateCollectionBase, type: string) {
6878
// If not drop, set drop properties to default 0
6979
if (!data.drop) {
7080
data.dropStart = data.dropPrice = data.dropReserve = 0;
7181
}
7282
const response = await ApillonApi.post<
7383
NftCollection & { collectionUuid: string }
74-
>(`${this.API_PREFIX}/${isEvm ? 'evm' : 'substrate'}`, data);
84+
>(`${this.API_PREFIX}/${type}`, data);
7585
return new NftCollection(response.collectionUuid, response);
7686
}
7787
}

packages/sdk/src/tests/nft.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,49 @@ describe('Nft tests', () => {
6767
expect(collection.isSoulbound).toEqual(false);
6868
});
6969

70+
test.only('creates a new unique collection', async () => {
71+
const uniqueCollectionData = {
72+
...nftData,
73+
maxSupply: 1000,
74+
isRevokable: true,
75+
isSoulbound: false,
76+
metadata: {
77+
'1': {
78+
name: 'Unique NFT 1',
79+
description: 'Description for Unique NFT 1',
80+
image: 'https://example.com/nft1.png',
81+
attributes: {
82+
value: 'Attribute Value 1',
83+
trait_type: 'Attribute Type 1',
84+
display_type: 'string',
85+
},
86+
},
87+
'2': {
88+
name: 'Unique NFT 2',
89+
description: 'Description for Unique NFT 2',
90+
image: 'https://example.com/nft2.png',
91+
attributes: {
92+
value: 'Attribute Value 2',
93+
trait_type: 'Attribute Type 2',
94+
display_type: 'string',
95+
},
96+
},
97+
},
98+
};
99+
100+
const collection = await nft.createUnique(uniqueCollectionData);
101+
expect(collection.uuid).toBeDefined();
102+
expect(collection.contractAddress).toBeDefined();
103+
expect(collection.symbol).toEqual('SDKT');
104+
expect(collection.name).toEqual('SDK Test');
105+
expect(collection.description).toEqual('Created from SDK tests');
106+
expect(collection.isAutoIncrement).toEqual(true);
107+
expect(collection.isRevokable).toEqual(true);
108+
expect(collection.isSoulbound).toEqual(false);
109+
110+
collectionUuid = collection.uuid;
111+
});
112+
70113
test('mints a new nft', async () => {
71114
const collection = nft.collection(collectionUuid);
72115
const res = await collection.mint({

packages/sdk/src/types/nfts.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export enum EvmChain {
88

99
export enum SubstrateChain {
1010
ASTAR = 8,
11+
UNIQUE = 11,
1112
}
1213

1314
export enum CollectionStatus {
@@ -57,16 +58,81 @@ export interface ICreateCollectionBase {
5758
}
5859

5960
export interface ICreateCollection extends ICreateCollectionBase {
61+
/**
62+
* Indicates if the collection is revokable (burnable).
63+
*/
6064
isRevokable: boolean;
65+
/**
66+
* Indicates if the collection is soulbound.
67+
*/
6168
isSoulbound: boolean;
69+
/**
70+
* If enabled, newly minted NFTs will have token IDs in sequential order.
71+
*/
6272
isAutoIncrement?: boolean;
73+
/**
74+
* The EVM chain on which the collection will be deployed.
75+
*/
6376
chain: EvmChain;
6477
}
6578

6679
export interface ICreateSubstrateCollection extends ICreateCollectionBase {
6780
chain: SubstrateChain;
6881
}
6982

83+
export interface IMetadataAttributes {
84+
/**
85+
* Trait value.
86+
*/
87+
value: string;
88+
/**
89+
* Name of the trait.
90+
*/
91+
trait_type: string;
92+
/**
93+
* Type for displaying trait (number, date,...).
94+
*/
95+
display_type: string;
96+
}
97+
98+
export interface IMetadata {
99+
/**
100+
* NFT name.
101+
*/
102+
name: string;
103+
/**
104+
* NFT description.
105+
*/
106+
description: string;
107+
/**
108+
* NFT image URL.
109+
*/
110+
image: string;
111+
/**
112+
* Array of NFT attributes.
113+
*/
114+
attributes: IMetadataAttributes;
115+
}
116+
117+
export interface ICreateUniqueCollection extends ICreateCollectionBase {
118+
/**
119+
* Maximum supply of the collection.
120+
*/
121+
maxSupply: number;
122+
/**
123+
* For revokable collection owner can destroy (burn) NFTs at any time.
124+
*/
125+
isRevokable: boolean;
126+
/**
127+
* Soulbound tokens are NFTs that are bound to wallet and not transferable. (default: false)
128+
*/
129+
isSoulbound: boolean;
130+
/**
131+
* Object containing metadata for different token ids.
132+
*/
133+
metadata: { [tokenId: string]: IMetadata };
134+
}
135+
70136
export interface ITransaction {
71137
chainId: number;
72138
transactionType: TransactionType;

0 commit comments

Comments
 (0)