1234567891011121314151617import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds';18import {IKeyringPair} from '@polkadot/types/types';19import {Contract} from 'web3-eth-contract';2021describe('NFT: Information getting', () => {22 let donor: IKeyringPair;23 let alice: IKeyringPair;2425 before(async function() {26 await usingEthPlaygrounds(async (helper, privateKey) => {27 donor = privateKey('//Alice');28 [alice] = await helper.arrange.createAccounts([10n], donor);29 });30 });31 32 itEth('totalSupply', async ({helper}) => {33 const collection = await helper.nft.mintCollection(alice, {});34 await collection.mintToken(alice);3536 const caller = await helper.eth.createAccountWithBalance(donor);3738 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);39 const totalSupply = await contract.methods.totalSupply().call();4041 expect(totalSupply).to.equal('1');42 });4344 itEth('balanceOf', async ({helper}) => {45 const collection = await helper.nft.mintCollection(alice, {});46 const caller = await helper.eth.createAccountWithBalance(donor);4748 await collection.mintToken(alice, {Ethereum: caller});49 await collection.mintToken(alice, {Ethereum: caller});50 await collection.mintToken(alice, {Ethereum: caller});5152 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);53 const balance = await contract.methods.balanceOf(caller).call();5455 expect(balance).to.equal('3');56 });5758 itEth('ownerOf', async ({helper}) => {59 const collection = await helper.nft.mintCollection(alice, {});60 const caller = await helper.eth.createAccountWithBalance(donor);6162 const token = await collection.mintToken(alice, {Ethereum: caller});6364 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);6566 const owner = await contract.methods.ownerOf(token.tokenId).call();6768 expect(owner).to.equal(caller);69 });70});7172describe('Check ERC721 token URI for NFT', () => {73 let donor: IKeyringPair;7475 before(async function() {76 await usingEthPlaygrounds(async (_helper, privateKey) => {77 donor = privateKey('//Alice');78 });79 });8081 async function setup(helper: EthUniqueHelper, tokenPrefix: string, propertyKey?: string, propertyValue?: string): Promise<{contract: Contract, nextTokenId: string}> {82 const owner = await helper.eth.createAccountWithBalance(donor);83 const receiver = helper.eth.createAccount();8485 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);86 let result = await collectionHelper.methods.createERC721MetadataCompatibleCollection('Mint collection', 'a', 'b', tokenPrefix).send();87 const collectionAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);88 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);89 90 const nextTokenId = await contract.methods.nextTokenId().call();91 expect(nextTokenId).to.be.equal('1');92 result = await contract.methods.mint(93 receiver,94 nextTokenId,95 ).send();9697 if (propertyKey && propertyValue) {98 99 await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send();100 }101102 const event = result.events.Transfer;103 expect(event.address).to.be.equal(collectionAddress);104 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');105 expect(event.returnValues.to).to.be.equal(receiver);106 expect(event.returnValues.tokenId).to.be.equal(nextTokenId);107108 return {contract, nextTokenId};109 }110111 itEth('Empty tokenURI', async ({helper}) => {112 const {contract, nextTokenId} = await setup(helper, '');113 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('');114 });115116 itEth('TokenURI from url', async ({helper}) => {117 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'url', 'Token URI');118 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Token URI');119 });120121 itEth('TokenURI from baseURI + tokenId', async ({helper}) => {122 const {contract, nextTokenId} = await setup(helper, 'BaseURI_');123 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + nextTokenId);124 });125126 itEth('TokenURI from baseURI + suffix', async ({helper}) => {127 const suffix = '/some/suffix';128 const {contract, nextTokenId} = await setup(helper, 'BaseURI_', 'suffix', suffix);129 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('BaseURI_' + suffix);130 });131});132133describe('NFT: Plain calls', () => {134 let donor: IKeyringPair;135 let alice: IKeyringPair;136137 before(async function() {138 await usingEthPlaygrounds(async (helper, privateKey) => {139 donor = privateKey('//Alice');140 [alice] = await helper.arrange.createAccounts([10n], donor);141 });142 });143144 itEth('Can perform mint()', async ({helper}) => {145 const owner = await helper.eth.createAccountWithBalance(donor);146 const receiver = helper.eth.createAccount();147148 const {collectionAddress} = await helper.eth.createNonfungibleCollection(owner, 'Minty', '6', '6');149 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);150 const nextTokenId = await contract.methods.nextTokenId().call();151152 expect(nextTokenId).to.be.equal('1');153 const result = await contract.methods.mintWithTokenURI(154 receiver,155 nextTokenId,156 'Test URI',157 ).send();158159 const event = result.events.Transfer;160 expect(event.address).to.be.equal(collectionAddress);161 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');162 expect(event.returnValues.to).to.be.equal(receiver);163 expect(event.returnValues.tokenId).to.be.equal(nextTokenId);164165 expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');166167 168 169 170 171 });172173 174 itEth.skip('Can perform mintBulk()', async ({helper}) => {175 const caller = await helper.eth.createAccountWithBalance(donor);176 const receiver = helper.eth.createAccount();177178 const collection = await helper.nft.mintCollection(alice);179 await collection.addAdmin(alice, {Ethereum: caller});180181 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);182 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);183 {184 const bulkSize = 3;185 const nextTokenId = await contract.methods.nextTokenId().call();186 expect(nextTokenId).to.be.equal('1');187 const result = await contract.methods.mintBulkWithTokenURI(188 receiver,189 Array.from({length: bulkSize}, (_, i) => (190 [+nextTokenId + i, `Test URI ${i}`]191 )),192 ).send({from: caller});193194 const events = result.events.Transfer.sort((a: any, b: any) => +a.returnValues.tokenId - b.returnValues.tokenId);195 for (let i = 0; i < bulkSize; i++) {196 const event = events[i];197 expect(event.address).to.equal(collectionAddress);198 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');199 expect(event.returnValues.to).to.equal(receiver);200 expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`);201202 expect(await contract.methods.tokenURI(+nextTokenId + i).call()).to.be.equal(`Test URI ${i}`);203 }204 }205 });206207 itEth('Can perform burn()', async ({helper}) => {208 const caller = await helper.eth.createAccountWithBalance(donor);209210 const collection = await helper.nft.mintCollection(alice, {});211 const {tokenId} = await collection.mintToken(alice, {Ethereum: caller});212213 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);214 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller);215216 {217 const result = await contract.methods.burn(tokenId).send({from: caller});218 219 const event = result.events.Transfer;220 expect(event.address).to.be.equal(collectionAddress);221 expect(event.returnValues.from).to.be.equal(caller);222 expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');223 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);224 }225 });226227 itEth('Can perform approve()', async ({helper}) => {228 const owner = await helper.eth.createAccountWithBalance(donor);229 const spender = helper.eth.createAccount();230231 const collection = await helper.nft.mintCollection(alice, {});232 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});233234 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);235 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);236237 {238 const result = await contract.methods.approve(spender, tokenId).send({from: owner});239240 const event = result.events.Approval;241 expect(event.address).to.be.equal(collectionAddress);242 expect(event.returnValues.owner).to.be.equal(owner);243 expect(event.returnValues.approved).to.be.equal(spender);244 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);245 }246 });247248 itEth('Can perform transferFrom()', async ({helper}) => {249 const owner = await helper.eth.createAccountWithBalance(donor);250 const spender = await helper.eth.createAccountWithBalance(donor);251 const receiver = helper.eth.createAccount();252253 const collection = await helper.nft.mintCollection(alice, {});254 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});255256 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);257 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);258259 await contract.methods.approve(spender, tokenId).send({from: owner});260261 {262 const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({from: spender});263264 const event = result.events.Transfer;265 expect(event.address).to.be.equal(collectionAddress);266 expect(event.returnValues.from).to.be.equal(owner);267 expect(event.returnValues.to).to.be.equal(receiver);268 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);269 }270271 {272 const balance = await contract.methods.balanceOf(receiver).call();273 expect(+balance).to.equal(1);274 }275276 {277 const balance = await contract.methods.balanceOf(owner).call();278 expect(+balance).to.equal(0);279 }280 });281282 itEth('Can perform transfer()', async ({helper}) => {283 const collection = await helper.nft.mintCollection(alice, {});284 const owner = await helper.eth.createAccountWithBalance(donor);285 const receiver = helper.eth.createAccount();286287 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});288289 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);290 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);291292 {293 const result = await contract.methods.transfer(receiver, tokenId).send({from: owner});294295 const event = result.events.Transfer;296 expect(event.address).to.be.equal(collectionAddress);297 expect(event.returnValues.from).to.be.equal(owner);298 expect(event.returnValues.to).to.be.equal(receiver);299 expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);300 }301302 {303 const balance = await contract.methods.balanceOf(owner).call();304 expect(+balance).to.equal(0);305 }306307 {308 const balance = await contract.methods.balanceOf(receiver).call();309 expect(+balance).to.equal(1);310 }311 });312});313314describe('NFT: Fees', () => {315 let donor: IKeyringPair;316 let alice: IKeyringPair;317318 before(async function() {319 await usingEthPlaygrounds(async (helper, privateKey) => {320 donor = privateKey('//Alice');321 [alice] = await helper.arrange.createAccounts([10n], donor);322 });323 });324 325 itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => {326 const owner = await helper.eth.createAccountWithBalance(donor);327 const spender = helper.eth.createAccount();328329 const collection = await helper.nft.mintCollection(alice, {});330 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});331332 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);333334 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner}));335 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));336 });337338 itEth('transferFrom() call fee is less than 0.2UNQ', async ({helper}) => {339 const owner = await helper.eth.createAccountWithBalance(donor);340 const spender = await helper.eth.createAccountWithBalance(donor);341342 const collection = await helper.nft.mintCollection(alice, {});343 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});344345 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);346347 await contract.methods.approve(spender, tokenId).send({from: owner});348349 const cost = await helper.eth.recordCallFee(spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({from: spender}));350 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));351 });352353 itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => {354 const owner = await helper.eth.createAccountWithBalance(donor);355 const receiver = helper.eth.createAccount();356357 const collection = await helper.nft.mintCollection(alice, {});358 const {tokenId} = await collection.mintToken(alice, {Ethereum: owner});359360 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner);361362 const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner}));363 expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));364 });365});366367describe('NFT: Substrate calls', () => {368 let donor: IKeyringPair;369 let alice: IKeyringPair;370371 before(async function() {372 await usingEthPlaygrounds(async (helper, privateKey) => {373 donor = privateKey('//Alice');374 [alice] = await helper.arrange.createAccounts([20n], donor);375 });376 });377378 itEth('Events emitted for mint()', async ({helper}) => {379 const collection = await helper.nft.mintCollection(alice, {});380 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);381 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');382383 const events: any = [];384 contract.events.allEvents((_: any, event: any) => {385 events.push(event);386 });387 const {tokenId} = await collection.mintToken(alice);388389 const event = events[0];390 expect(event.event).to.be.equal('Transfer');391 expect(event.address).to.be.equal(collectionAddress);392 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');393 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(alice.address));394 expect(event.returnValues.tokenId).to.be.equal(tokenId.toString());395 });396397 itEth('Events emitted for burn()', async ({helper}) => {398 const collection = await helper.nft.mintCollection(alice, {});399 const token = await collection.mintToken(alice);400401 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);402 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');403 404 const events: any = [];405 contract.events.allEvents((_: any, event: any) => {406 events.push(event);407 });408409 await token.burn(alice);410411 const event = events[0];412 expect(event.event).to.be.equal('Transfer');413 expect(event.address).to.be.equal(collectionAddress);414 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));415 expect(event.returnValues.to).to.be.equal('0x0000000000000000000000000000000000000000');416 expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());417 });418419 itEth('Events emitted for approve()', async ({helper}) => {420 const receiver = helper.eth.createAccount();421422 const collection = await helper.nft.mintCollection(alice, {});423 const token = await collection.mintToken(alice);424425 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);426 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');427 428 const events: any = [];429 contract.events.allEvents((_: any, event: any) => {430 events.push(event);431 });432433 await token.approve(alice, {Ethereum: receiver});434435 const event = events[0];436 expect(event.event).to.be.equal('Approval');437 expect(event.address).to.be.equal(collectionAddress);438 expect(event.returnValues.owner).to.be.equal(helper.address.substrateToEth(alice.address));439 expect(event.returnValues.approved).to.be.equal(receiver);440 expect(event.returnValues.tokenId).to.be.equal(token.tokenId.toString());441 });442443 itEth('Events emitted for transferFrom()', async ({helper}) => {444 const [bob] = await helper.arrange.createAccounts([10n], donor);445 const receiver = helper.eth.createAccount();446447 const collection = await helper.nft.mintCollection(alice, {});448 const token = await collection.mintToken(alice);449 await token.approve(alice, {Substrate: bob.address});450451 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);452 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');453 454 const events: any = [];455 contract.events.allEvents((_: any, event: any) => {456 events.push(event);457 });458459 await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver});460 461 const event = events[0];462 expect(event.address).to.be.equal(collectionAddress);463 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));464 expect(event.returnValues.to).to.be.equal(receiver);465 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);466 });467468 itEth('Events emitted for transfer()', async ({helper}) => {469 const receiver = helper.eth.createAccount();470471 const collection = await helper.nft.mintCollection(alice, {});472 const token = await collection.mintToken(alice);473474 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);475 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft');476 477 const events: any = [];478 contract.events.allEvents((_: any, event: any) => {479 events.push(event);480 });481482 await token.transfer(alice, {Ethereum: receiver});483 484 const event = events[0];485 expect(event.address).to.be.equal(collectionAddress);486 expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address));487 expect(event.returnValues.to).to.be.equal(receiver);488 expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);489 });490});491492describe('Common metadata', () => {493 let donor: IKeyringPair;494 let alice: IKeyringPair;495496 before(async function() {497 await usingEthPlaygrounds(async (helper, privateKey) => {498 donor = privateKey('//Alice');499 [alice] = await helper.arrange.createAccounts([20n], donor);500 });501 });502503 itEth('Returns collection name', async ({helper}) => {504 const caller = await helper.eth.createAccountWithBalance(donor);505 const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});506507 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);508 const name = await contract.methods.name().call();509 expect(name).to.equal('oh River');510 });511512 itEth('Returns symbol name', async ({helper}) => {513 const caller = await helper.eth.createAccountWithBalance(donor);514 const collection = await helper.nft.mintCollection(alice, {name: 'oh River', tokenPrefix: 'CHANGE'});515516 const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller);517 const symbol = await contract.methods.symbol().call();518 expect(symbol).to.equal('CHANGE');519 });520});