1234567891011121314151617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {expect, itEth, usingEthPlaygrounds} from './util';202122describe('Create NFT collection from EVM', () => {23 let donor: IKeyringPair;2425 before(async function () {26 await usingEthPlaygrounds(async (_helper, privateKey) => {27 donor = await privateKey({filename: __filename});28 });29 });3031 itEth('Create collection', async ({helper}) => {32 const owner = await helper.eth.createAccountWithBalance(donor);3334 const name = 'CollectionEVM';35 const description = 'Some description';36 const prefix = 'token prefix';3738 39 const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;40 const {collectionId, collectionAddress, events} = await helper.eth.createNFTCollection(owner, name, description, prefix);41 42 expect(events).to.be.deep.equal([43 {44 address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',45 event: 'CollectionCreated',46 args: {47 owner: owner,48 collectionId: collectionAddress,49 },50 },51 ]);52 53 const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;5455 const collection = helper.nft.getCollectionObject(collectionId);56 const data = (await collection.getData())!;5758 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);59 expect(collectionId).to.be.eq(collectionCountAfter);60 expect(data.name).to.be.eq(name);61 expect(data.description).to.be.eq(description);62 expect(data.raw.tokenPrefix).to.be.eq(prefix);63 expect(data.raw.mode).to.be.eq('NFT');6465 const options = await collection.getOptions();6667 expect(options.tokenPropertyPermissions).to.be.empty;68 });6970 itEth('Create collection with properties', async ({helper}) => {71 const owner = await helper.eth.createAccountWithBalance(donor);7273 const name = 'CollectionEVM';74 const description = 'Some description';75 const prefix = 'token prefix';76 const baseUri = 'BaseURI';7778 const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);7980 expect(events).to.be.deep.equal([81 {82 address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F',83 event: 'CollectionCreated',84 args: {85 owner: owner,86 collectionId: collectionAddress,87 },88 },89 ]);9091 const collection = helper.nft.getCollectionObject(collectionId);92 const data = (await collection.getData())!;93 94 expect(data.name).to.be.eq(name);95 expect(data.description).to.be.eq(description);96 expect(data.raw.tokenPrefix).to.be.eq(prefix);97 expect(data.raw.mode).to.be.eq('NFT');9899 const options = await collection.getOptions();100 expect(options.tokenPropertyPermissions).to.be.deep.equal([101 {102 key: 'URI',103 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},104 },105 {106 key: 'URISuffix',107 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},108 },109 ]);110 });111112 113 itEth.skip('Check collection address exist', async ({helper}) => {114 const owner = await helper.eth.createAccountWithBalance(donor);115116 const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;117 const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);118 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);119120 expect(await collectionHelpers.methods121 .isCollectionExist(expectedCollectionAddress)122 .call()).to.be.false;123124 await collectionHelpers.methods125 .createNFTCollection('A', 'A', 'A')126 .send({value: Number(2n * helper.balance.getOneTokenNominal())});127128 expect(await collectionHelpers.methods129 .isCollectionExist(expectedCollectionAddress)130 .call()).to.be.true;131 });132133 itEth('Set sponsorship', async ({helper}) => {134 const owner = await helper.eth.createAccountWithBalance(donor);135 const sponsor = await helper.eth.createAccountWithBalance(donor);136 const ss58Format = helper.chain.getChainProperties().ss58Format;137 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');138139 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);140 await collection.methods.setCollectionSponsor(sponsor).send();141142 let data = (await helper.nft.getData(collectionId))!;143 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));144145 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');146147 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);148 await sponsorCollection.methods.confirmCollectionSponsorship().send();149150 data = (await helper.nft.getData(collectionId))!;151 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));152 });153154 itEth('Set limits', async ({helper}) => {155 const owner = await helper.eth.createAccountWithBalance(donor);156 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'FLO');157 const limits = {158 accountTokenOwnershipLimit: 1000,159 sponsoredDataSize: 1024,160 sponsoredDataRateLimit: 30,161 tokenLimit: 1000000,162 sponsorTransferTimeout: 6,163 sponsorApproveTimeout: 6,164 ownerCanTransfer: false,165 ownerCanDestroy: false,166 transfersEnabled: false,167 };168169 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);170 await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();171 await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();172 await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();173 await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();174 await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();175 await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();176 await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();177 await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();178 await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();179180 const data = (await helper.nft.getData(collectionId))!;181 expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit);182 expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize);183 expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit);184 expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit);185 expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout);186 expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout);187 expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer);188 expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy);189 expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled);190 });191192 itEth('Collection address exist', async ({helper}) => {193 const owner = await helper.eth.createAccountWithBalance(donor);194 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';195 expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)196 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())197 .to.be.false;198199 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC');200 expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)201 .methods.isCollectionExist(collectionAddress).call())202 .to.be.true;203 });204});205206describe('(!negative tests!) Create NFT collection from EVM', () => {207 let donor: IKeyringPair;208 let nominal: bigint;209210 before(async function () {211 await usingEthPlaygrounds(async (helper, privateKey) => {212 donor = await privateKey({filename: __filename});213 nominal = helper.balance.getOneTokenNominal();214 });215 });216217 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {218 const owner = await helper.eth.createAccountWithBalance(donor);219 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);220 {221 const MAX_NAME_LENGTH = 64;222 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);223 const description = 'A';224 const tokenPrefix = 'A';225226 await expect(collectionHelper.methods227 .createNFTCollection(collectionName, description, tokenPrefix)228 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);229230 }231 {232 const MAX_DESCRIPTION_LENGTH = 256;233 const collectionName = 'A';234 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);235 const tokenPrefix = 'A';236 await expect(collectionHelper.methods237 .createNFTCollection(collectionName, description, tokenPrefix)238 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);239 }240 {241 const MAX_TOKEN_PREFIX_LENGTH = 16;242 const collectionName = 'A';243 const description = 'A';244 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);245 await expect(collectionHelper.methods246 .createNFTCollection(collectionName, description, tokenPrefix)247 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);248 }249 });250251 itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {252 const owner = await helper.eth.createAccountWithBalance(donor);253 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);254 await expect(collectionHelper.methods255 .createNFTCollection('Peasantry', 'absolutely anything', 'CVE')256 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');257 });258259 itEth('(!negative test!) Check owner', async ({helper}) => {260 const owner = await helper.eth.createAccountWithBalance(donor);261 const malfeasant = helper.eth.createAccount();262 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');263 const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant);264 const EXPECTED_ERROR = 'NoPermission';265 {266 const sponsor = await helper.eth.createAccountWithBalance(donor);267 await expect(malfeasantCollection.methods268 .setCollectionSponsor(sponsor)269 .call()).to.be.rejectedWith(EXPECTED_ERROR);270271 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);272 await expect(sponsorCollection.methods273 .confirmCollectionSponsorship()274 .call()).to.be.rejectedWith('caller is not set as sponsor');275 }276 {277 await expect(malfeasantCollection.methods278 .setCollectionLimit('account_token_ownership_limit', '1000')279 .call()).to.be.rejectedWith(EXPECTED_ERROR);280 }281 });282283 itEth('(!negative test!) Set limits', async ({helper}) => {284 const owner = await helper.eth.createAccountWithBalance(donor);285 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');286 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);287 await expect(collectionEvm.methods288 .setCollectionLimit('badLimit', 'true')289 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');290 });291292 itEth('destroyCollection', async ({helper}) => {293 const owner = await helper.eth.createAccountWithBalance(donor);294 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');295 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);296297298 const result = await collectionHelper.methods299 .destroyCollection(collectionAddress)300 .send({from: owner});301302 const events = helper.eth.normalizeEvents(result.events);303 304 expect(events).to.be.deep.equal([305 {306 address: collectionHelper.options.address,307 event: 'CollectionDestroyed',308 args: {309 collectionId: collectionAddress,310 },311 },312 ]);313314 expect(await collectionHelper.methods315 .isCollectionExist(collectionAddress)316 .call()).to.be.false;317 });318});