1234567891011121314151617import {evmToAddress} from '@polkadot/util-crypto';18import {IKeyringPair} from '@polkadot/types/types';19import {expect, itEth, usingEthPlaygrounds} from './util/playgrounds';202122describe('Create NFT collection from EVM', () => {23 let donor: IKeyringPair;2425 before(async function() {26 await usingEthPlaygrounds(async (_helper, privateKey) => {27 donor = privateKey('//Alice');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} = await helper.eth.createNFTCollection(owner, name, description, prefix);41 const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;4243 const collection = helper.nft.getCollectionObject(collectionId);44 const data = (await collection.getData())!;45 46 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);47 expect(collectionId).to.be.eq(collectionCountAfter);48 expect(data.name).to.be.eq(name);49 expect(data.description).to.be.eq(description);50 expect(data.raw.tokenPrefix).to.be.eq(prefix);51 expect(data.raw.mode).to.be.eq('NFT');5253 const options = await collection.getOptions();5455 expect(options.tokenPropertyPermissions).to.be.empty;56 });5758 itEth('Create collection with properties', async ({helper}) => {59 const owner = await helper.eth.createAccountWithBalance(donor);6061 const name = 'CollectionEVM';62 const description = 'Some description';63 const prefix = 'token prefix';64 const baseUri = 'BaseURI';6566 67 const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;68 const {collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri);69 const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created;7071 const collection = helper.nft.getCollectionObject(collectionId);72 const data = (await collection.getData())!;73 74 expect(collectionCountAfter - collectionCountBefore).to.be.eq(1);75 expect(collectionId).to.be.eq(collectionCountAfter);76 expect(data.name).to.be.eq(name);77 expect(data.description).to.be.eq(description);78 expect(data.raw.tokenPrefix).to.be.eq(prefix);79 expect(data.raw.mode).to.be.eq('NFT');8081 const options = await collection.getOptions();82 expect(options.tokenPropertyPermissions).to.be.deep.equal([83 {84 key: 'URI',85 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},86 },87 {88 key: 'URISuffix',89 permission: {mutable: true, collectionAdmin: true, tokenOwner: false},90 },91 ]);92 });9394 95 itEth('Check collection address exist', async ({helper}) => {96 const owner = await helper.eth.createAccountWithBalance(donor);9798 const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1;99 const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId);100 const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner);101102 expect(await collectionHelpers.methods103 .isCollectionExist(expectedCollectionAddress)104 .call()).to.be.false;105106 await collectionHelpers.methods107 .createNFTCollection('A', 'A', 'A')108 .send({value: Number(2n * helper.balance.getOneTokenNominal())});109 110 expect(await collectionHelpers.methods111 .isCollectionExist(expectedCollectionAddress)112 .call()).to.be.true;113 });114 115 itEth('Set sponsorship', async ({helper}) => {116 const owner = await helper.eth.createAccountWithBalance(donor);117 const sponsor = await helper.eth.createAccountWithBalance(donor);118 const ss58Format = helper.chain.getChainProperties().ss58Format;119 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');120121 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);122 await collection.methods.setCollectionSponsor(sponsor).send();123124 let data = (await helper.nft.getData(collectionId))!;125 expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));126127 await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');128129 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);130 await sponsorCollection.methods.confirmCollectionSponsorship().send();131132 data = (await helper.nft.getData(collectionId))!;133 expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));134 });135136 itEth('Set limits', async ({helper}) => {137 const owner = await helper.eth.createAccountWithBalance(donor);138 const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'FLO');139 const limits = {140 accountTokenOwnershipLimit: 1000,141 sponsoredDataSize: 1024,142 sponsoredDataRateLimit: 30,143 tokenLimit: 1000000,144 sponsorTransferTimeout: 6,145 sponsorApproveTimeout: 6,146 ownerCanTransfer: false,147 ownerCanDestroy: false,148 transfersEnabled: false,149 };150151 const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);152 await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send();153 await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send();154 await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send();155 await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send();156 await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send();157 await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send();158 await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send();159 await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send();160 await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send();161 162 const data = (await helper.nft.getData(collectionId))!;163 expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit);164 expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize);165 expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit);166 expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit);167 expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout);168 expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout);169 expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer);170 expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy);171 expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled);172 });173174 itEth('Collection address exist', async ({helper}) => {175 const owner = await helper.eth.createAccountWithBalance(donor);176 const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233';177 expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection)178 .methods.isCollectionExist(collectionAddressForNonexistentCollection).call())179 .to.be.false;180 181 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC');182 expect(await helper.ethNativeContract.collectionHelpers(collectionAddress)183 .methods.isCollectionExist(collectionAddress).call())184 .to.be.true;185 });186});187188describe('(!negative tests!) Create NFT collection from EVM', () => {189 let donor: IKeyringPair;190 let nominal: bigint;191192 before(async function() {193 await usingEthPlaygrounds(async (helper, privateKey) => {194 donor = privateKey('//Alice');195 nominal = helper.balance.getOneTokenNominal();196 });197 });198199 itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => {200 const owner = await helper.eth.createAccountWithBalance(donor);201 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);202 {203 const MAX_NAME_LENGTH = 64;204 const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1);205 const description = 'A';206 const tokenPrefix = 'A';207208 await expect(collectionHelper.methods209 .createNFTCollection(collectionName, description, tokenPrefix)210 .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH);211 212 }213 {214 const MAX_DESCRIPTION_LENGTH = 256;215 const collectionName = 'A';216 const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1);217 const tokenPrefix = 'A';218 await expect(collectionHelper.methods219 .createNFTCollection(collectionName, description, tokenPrefix)220 .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH);221 }222 {223 const MAX_TOKEN_PREFIX_LENGTH = 16;224 const collectionName = 'A';225 const description = 'A';226 const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1);227 await expect(collectionHelper.methods228 .createNFTCollection(collectionName, description, tokenPrefix)229 .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH);230 }231 });232 233 itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {234 const owner = await helper.eth.createAccountWithBalance(donor);235 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);236 await expect(collectionHelper.methods237 .createNFTCollection('Peasantry', 'absolutely anything', 'CVE')238 .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');239 });240241 itEth('(!negative test!) Check owner', async ({helper}) => {242 const owner = await helper.eth.createAccountWithBalance(donor);243 const malfeasant = helper.eth.createAccount();244 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR');245 const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant);246 const EXPECTED_ERROR = 'NoPermission';247 {248 const sponsor = await helper.eth.createAccountWithBalance(donor);249 await expect(malfeasantCollection.methods250 .setCollectionSponsor(sponsor)251 .call()).to.be.rejectedWith(EXPECTED_ERROR);252 253 const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);254 await expect(sponsorCollection.methods255 .confirmCollectionSponsorship()256 .call()).to.be.rejectedWith('caller is not set as sponsor');257 }258 {259 await expect(malfeasantCollection.methods260 .setCollectionLimit('account_token_ownership_limit', '1000')261 .call()).to.be.rejectedWith(EXPECTED_ERROR);262 }263 });264265 itEth('(!negative test!) Set limits', async ({helper}) => {266 const owner = await helper.eth.createAccountWithBalance(donor);267 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');268 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);269 await expect(collectionEvm.methods270 .setCollectionLimit('badLimit', 'true')271 .call()).to.be.rejectedWith('unknown boolean limit "badLimit"');272 });273});