git.delta.rocks / unique-network / refs/commits / 36c7382c2750

difftreelog

test mintBulk/metadata api

Yaroslav Bolyukin2021-09-01parent: #ac37b71.patch.diff
in: master

2 files changed

modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
before · tests/src/eth/nonFungible.test.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import privateKey from '../substrate/privateKey';7import { approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';9import { evmToAddress } from '@polkadot/util-crypto';10import nonFungibleAbi from './nonFungibleAbi.json';11import { expect } from 'chai';12import waitNewBlocks from '../substrate/wait-new-blocks';13import { submitTransactionAsync } from '../substrate/substrate-api';1415describe('NFT: Information getting', () => {16  itWeb3('totalSupply', async ({ api, web3 }) => {17    const collection = await createCollectionExpectSuccess({18      mode: { type: 'NFT' },19    });20    const alice = privateKey('//Alice');21    const caller = await createEthAccountWithBalance(api, web3);2223    await createItemExpectSuccess(alice, collection, 'NFT', { substrate: alice.address });2425    const address = collectionIdToAddress(collection);26    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});27    const totalSupply = await contract.methods.totalSupply().call();2829    // FIXME: always equals to 0, because this method is not implemented30    expect(totalSupply).to.equal('0');31  });3233  itWeb3('balanceOf', async ({ api, web3 }) => {34    const collection = await createCollectionExpectSuccess({35      mode: { type: 'NFT' },36    });37    const alice = privateKey('//Alice');3839    const caller = await createEthAccountWithBalance(api, web3);40    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });41    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });42    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });4344    const address = collectionIdToAddress(collection);45    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});46    const balance = await contract.methods.balanceOf(caller).call();4748    expect(balance).to.equal('3');49  });5051  itWeb3('ownerOf', async ({ api, web3 }) => {52    const collection = await createCollectionExpectSuccess({53      mode: { type: 'NFT' },54    });55    const alice = privateKey('//Alice');5657    const caller = await createEthAccountWithBalance(api, web3);58    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });5960    const address = collectionIdToAddress(collection);61    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});62    const owner = await contract.methods.ownerOf(tokenId).call();6364    expect(owner).to.equal(caller);65  });66});6768describe('NFT: Plain calls', () => {69  itWeb3('Can perform mint()', async ({ web3, api }) => {70    const collection = await createCollectionExpectSuccess({71      mode: { type: 'NFT' },72    });73    const alice = privateKey('//Alice');7475    const caller = await createEthAccountWithBalance(api, web3);76    const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: caller });77    await submitTransactionAsync(alice, changeAdminTx);78    const receiver = createEthAccount(web3);7980    const address = collectionIdToAddress(collection);81    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});8283    {84      const nextTokenId = await contract.methods.nextTokenId().call();85      expect(nextTokenId).to.be.equal('1');86      const result = await contract.methods.mintWithTokenURI(87        receiver,88        nextTokenId,89        'Test URI',90      ).send({from: caller});91      const events = normalizeEvents(result.events);9293      expect(events).to.be.deep.equal([94        {95          address,96          event: 'Transfer',97          args: {98            from: '0x0000000000000000000000000000000000000000',99            to: receiver,100            tokenId: nextTokenId,101          },102        },103      ]);104105      await waitNewBlocks(api, 1);106      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');107    }108  });109110  itWeb3('Can perform burn()', async ({ web3, api }) => {111    const collection = await createCollectionExpectSuccess({112      mode: {type: 'NFT'},113    });114    const alice = privateKey('//Alice');115116    const owner = await createEthAccountWithBalance(api, web3);117118    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });119    120    const address = collectionIdToAddress(collection);121    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});122123    {124      const result = await contract.methods.burn(tokenId).send({ from: owner });125      const events = normalizeEvents(result.events);126      127      expect(events).to.be.deep.equal([128        {129          address,130          event: 'Transfer',131          args: {132            from: owner,133            to: '0x0000000000000000000000000000000000000000',134            tokenId: tokenId.toString(),135          },136        },137      ]);138    }139  });140141  itWeb3('Can perform approve()', async ({ web3, api }) => {142    const collection = await createCollectionExpectSuccess({143      mode: { type: 'NFT' },144    });145    const alice = privateKey('//Alice');146147    const owner = createEthAccount(web3);148    await transferBalanceToEth(api, alice, owner, 999999999999999);149150    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });151152    const spender = createEthAccount(web3);153154    const address = collectionIdToAddress(collection);155    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);156157    {158      const result = await contract.methods.approve(spender, tokenId).send({ from: owner, gas: '0x1000000', gasPrice: '0x01' });159      const events = normalizeEvents(result.events);160161      expect(events).to.be.deep.equal([162        {163          address,164          event: 'Approval',165          args: {166            owner,167            approved: spender,168            tokenId: tokenId.toString(),169          },170        },171      ]);172    }173  });174175  itWeb3('Can perform transferFrom()', async ({ web3, api }) => {176    const collection = await createCollectionExpectSuccess({177      mode: { type: 'NFT' },178    });179    const alice = privateKey('//Alice');180181    const owner = createEthAccount(web3);182    await transferBalanceToEth(api, alice, owner, 999999999999999);183184    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });185186    const spender = createEthAccount(web3);187    await transferBalanceToEth(api, alice, spender, 999999999999999);188189    const receiver = createEthAccount(web3);190191    const address = collectionIdToAddress(collection);192    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});193194    await contract.methods.approve(spender, tokenId).send({ from: owner });195196    {197      const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({ from: spender });198      const events = normalizeEvents(result.events);199      expect(events).to.be.deep.equal([200        {201          address,202          event: 'Transfer',203          args: {204            from: owner,205            to: receiver,206            tokenId: tokenId.toString(),207          },208        },209      ]);210    }211212    {213      const balance = await contract.methods.balanceOf(receiver).call();214      expect(+balance).to.equal(1);215    }216217    {218      const balance = await contract.methods.balanceOf(owner).call();219      expect(+balance).to.equal(0);220    }221  });222223  itWeb3('Can perform transfer()', async ({ web3, api }) => {224    const collection = await createCollectionExpectSuccess({225      mode: { type: 'NFT' },226    });227    const alice = privateKey('//Alice');228229    const owner = createEthAccount(web3);230    await transferBalanceToEth(api, alice, owner, 999999999999999);231232    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });233234    const receiver = createEthAccount(web3);235    await transferBalanceToEth(api, alice, receiver, 999999999999999);236237    const address = collectionIdToAddress(collection);238    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});239240    {241      const result = await contract.methods.transfer(receiver, tokenId).send({ from: owner });242      await waitNewBlocks(api, 1);243      const events = normalizeEvents(result.events);244      expect(events).to.be.deep.equal([245        {246          address,247          event: 'Transfer',248          args: {249            from: owner,250            to: receiver,251            tokenId: tokenId.toString(),252          },253        },254      ]);255    }256257    {258      const balance = await contract.methods.balanceOf(owner).call();259      expect(+balance).to.equal(0);260    }261262    {263      const balance = await contract.methods.balanceOf(receiver).call();264      expect(+balance).to.equal(1);265    }266  });267});268269describe('NFT: Fees', () => {270  itWeb3('approve() call fee is less than 0.2UNQ', async ({ web3, api }) => {271    const collection = await createCollectionExpectSuccess({272      mode: { type: 'NFT' },273    });274    const alice = privateKey('//Alice');275276    const owner = await createEthAccountWithBalance(api, web3);277    const spender = createEthAccount(web3);278279    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });280281    const address = collectionIdToAddress(collection);282    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });283284    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({ from: owner }));285    expect(cost < BigInt(0.2 * Number(UNIQUE)));286  });287288  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({ web3, api }) => {289    const collection = await createCollectionExpectSuccess({290      mode: { type: 'NFT' },291    });292    const alice = privateKey('//Alice');293  294    const owner = await createEthAccountWithBalance(api, web3);295    const spender = await createEthAccountWithBalance(api, web3);296297    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });298299    const address = collectionIdToAddress(collection);300    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });301302    await contract.methods.approve(spender, tokenId).send({ from: owner });303304    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({ from: spender }));305    expect(cost < BigInt(0.2 * Number(UNIQUE)));306  });307308  itWeb3('transfer() call fee is less than 0.2UNQ', async ({ web3, api }) => {309    const collection = await createCollectionExpectSuccess({310      mode: { type: 'NFT' },311    });312    const alice = privateKey('//Alice');313314    const owner = await createEthAccountWithBalance(api, web3);315    const receiver = createEthAccount(web3);316317    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });318319    const address = collectionIdToAddress(collection);320    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });321322    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({ from: owner }));323    expect(cost < BigInt(0.2 * Number(UNIQUE)));324  });325});326327describe('NFT: Substrate calls', () => {328  itWeb3('Events emitted for mint()', async ({ web3 }) => {329    const collection = await createCollectionExpectSuccess({330      mode: { type: 'NFT' },331    });332    const alice = privateKey('//Alice');333334    const address = collectionIdToAddress(collection);335    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);336337    let tokenId: number;338    const events = await recordEvents(contract, async () => {339      tokenId = await createItemExpectSuccess(alice, collection, 'NFT');340    });341342    expect(events).to.be.deep.equal([343      {344        address,345        event: 'Transfer',346        args: {347          from: '0x0000000000000000000000000000000000000000',348          to: subToEth(alice.address),349          tokenId: tokenId!.toString(),350        },351      },352    ]);353  });354355  itWeb3('Events emitted for burn()', async ({ web3 }) => {356    const collection = await createCollectionExpectSuccess({357      mode: { type: 'NFT' },358    });359    const alice = privateKey('//Alice');360361    const address = collectionIdToAddress(collection);362    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);363364    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');365    const events = await recordEvents(contract, async () => {366      await burnItemExpectSuccess(alice, collection, tokenId);367    });368369    expect(events).to.be.deep.equal([370      {371        address,372        event: 'Transfer',373        args: {374          from: subToEth(alice.address),375          to: '0x0000000000000000000000000000000000000000',376          tokenId: tokenId.toString(),377        },378      },379    ]);380  });381382  itWeb3('Events emitted for approve()', async ({ web3 }) => {383    const collection = await createCollectionExpectSuccess({384      mode: { type: 'NFT' },385    });386    const alice = privateKey('//Alice');387388    const receiver = createEthAccount(web3);389390    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');391392    const address = collectionIdToAddress(collection);393    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);394395    const events = await recordEvents(contract, async () => {396      await approveExpectSuccess(collection, tokenId, alice, { ethereum: receiver }, 1);397    });398399    expect(events).to.be.deep.equal([400      {401        address,402        event: 'Approval',403        args: {404          owner: subToEth(alice.address),405          approved: receiver,406          tokenId: tokenId.toString(),407        },408      },409    ]);410  });411412  itWeb3('Events emitted for transferFrom()', async ({ web3 }) => {413    const collection = await createCollectionExpectSuccess({414      mode: { type: 'NFT' },415    });416    const alice = privateKey('//Alice');417    const bob = privateKey('//Bob');418419    const receiver = createEthAccount(web3);420421    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');422    await approveExpectSuccess(collection, tokenId, alice, bob, 1);423424    const address = collectionIdToAddress(collection);425    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);426427    const events = await recordEvents(contract, async () => {428      await transferFromExpectSuccess(collection, tokenId, bob, alice, { ethereum: receiver }, 1, 'NFT');429    });430431    expect(events).to.be.deep.equal([432      {433        address,434        event: 'Transfer',435        args: {436          from: subToEth(alice.address),437          to: receiver,438          tokenId: tokenId.toString(),439        },440      },441    ]);442  });443444  itWeb3('Events emitted for transfer()', async ({ web3 }) => {445    const collection = await createCollectionExpectSuccess({446      mode: { type: 'NFT' },447    });448    const alice = privateKey('//Alice');449450    const receiver = createEthAccount(web3);451452    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');453454    const address = collectionIdToAddress(collection);455    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);456457    const events = await recordEvents(contract, async () => {458      await transferExpectSuccess(collection, tokenId, alice, { ethereum: receiver }, 1, 'NFT');459    });460461    expect(events).to.be.deep.equal([462      {463        address,464        event: 'Transfer',465        args: {466          from: subToEth(alice.address),467          to: receiver,468          tokenId: tokenId.toString(),469        },470      },471    ]);472  });473});
after · tests/src/eth/nonFungible.test.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import privateKey from '../substrate/privateKey';7import { approveExpectSuccess, burnItemExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE } from '../util/helpers';8import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth } from './util/helpers';9import nonFungibleAbi from './nonFungibleAbi.json';10import { expect } from 'chai';11import waitNewBlocks from '../substrate/wait-new-blocks';12import { submitTransactionAsync } from '../substrate/substrate-api';1314describe('NFT: Information getting', () => {15  itWeb3('totalSupply', async ({ api, web3 }) => {16    const collection = await createCollectionExpectSuccess({17      mode: { type: 'NFT' },18    });19    const alice = privateKey('//Alice');20    const caller = await createEthAccountWithBalance(api, web3);2122    await createItemExpectSuccess(alice, collection, 'NFT', { substrate: alice.address });2324    const address = collectionIdToAddress(collection);25    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});26    const totalSupply = await contract.methods.totalSupply().call();2728    // FIXME: always equals to 0, because this method is not implemented29    expect(totalSupply).to.equal('0');30  });3132  itWeb3('balanceOf', async ({ api, web3 }) => {33    const collection = await createCollectionExpectSuccess({34      mode: { type: 'NFT' },35    });36    const alice = privateKey('//Alice');3738    const caller = await createEthAccountWithBalance(api, web3);39    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });40    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });41    await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });4243    const address = collectionIdToAddress(collection);44    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});45    const balance = await contract.methods.balanceOf(caller).call();4647    expect(balance).to.equal('3');48  });4950  itWeb3('ownerOf', async ({ api, web3 }) => {51    const collection = await createCollectionExpectSuccess({52      mode: { type: 'NFT' },53    });54    const alice = privateKey('//Alice');5556    const caller = await createEthAccountWithBalance(api, web3);57    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: caller });5859    const address = collectionIdToAddress(collection);60    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});61    const owner = await contract.methods.ownerOf(tokenId).call();6263    expect(owner).to.equal(caller);64  });65});6667describe('NFT: Plain calls', () => {68  itWeb3('Can perform mint()', async ({ web3, api }) => {69    const collection = await createCollectionExpectSuccess({70      mode: { type: 'NFT' },71    });72    const alice = privateKey('//Alice');7374    const caller = await createEthAccountWithBalance(api, web3);75    const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: caller });76    await submitTransactionAsync(alice, changeAdminTx);77    const receiver = createEthAccount(web3);7879    const address = collectionIdToAddress(collection);80    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});8182    {83      const nextTokenId = await contract.methods.nextTokenId().call();84      expect(nextTokenId).to.be.equal('1');85      const result = await contract.methods.mintWithTokenURI(86        receiver,87        nextTokenId,88        'Test URI',89      ).send({from: caller});90      const events = normalizeEvents(result.events);9192      expect(events).to.be.deep.equal([93        {94          address,95          event: 'Transfer',96          args: {97            from: '0x0000000000000000000000000000000000000000',98            to: receiver,99            tokenId: nextTokenId,100          },101        },102      ]);103104      await waitNewBlocks(api, 1);105      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');106    }107  });108  itWeb3.only('Can perform mintBulk()', async ({ web3, api }) => {109    const collection = await createCollectionExpectSuccess({110      mode: { type: 'NFT' },111    });112    const alice = privateKey('//Alice');113114    const caller = await createEthAccountWithBalance(api, web3);115    const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: caller });116    await submitTransactionAsync(alice, changeAdminTx);117    const receiver = createEthAccount(web3);118119    const address = collectionIdToAddress(collection);120    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});121122    {123      const nextTokenId = await contract.methods.nextTokenId().call();124      expect(nextTokenId).to.be.equal('1');125      const result = await contract.methods.mintBulkWithTokenURI(126        receiver,127        [128          [nextTokenId, 'Test URI 0'],129          [+nextTokenId + 1, 'Test URI 1'],130          [+nextTokenId + 2, 'Test URI 2'],131        ],132      ).send({ from: caller });133      const events = normalizeEvents(result.events);134135      expect(events).to.be.deep.equal([136        {137          address,138          event: 'Transfer',139          args: {140            from: '0x0000000000000000000000000000000000000000',141            to: receiver,142            tokenId: nextTokenId,143          },144        },145        {146          address,147          event: 'Transfer',148          args: {149            from: '0x0000000000000000000000000000000000000000',150            to: receiver,151            tokenId: String(+nextTokenId + 1),152          },153        },154        {155          address,156          event: 'Transfer',157          args: {158            from: '0x0000000000000000000000000000000000000000',159            to: receiver,160            tokenId: String(+nextTokenId + 2),161          },162        },163      ]);164165      await waitNewBlocks(api, 1);166      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');167      expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');168      expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');169    }170  });171172  itWeb3('Can perform burn()', async ({ web3, api }) => {173    const collection = await createCollectionExpectSuccess({174      mode: {type: 'NFT'},175    });176    const alice = privateKey('//Alice');177178    const owner = await createEthAccountWithBalance(api, web3);179180    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });181    182    const address = collectionIdToAddress(collection);183    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});184185    {186      const result = await contract.methods.burn(tokenId).send({ from: owner });187      const events = normalizeEvents(result.events);188      189      expect(events).to.be.deep.equal([190        {191          address,192          event: 'Transfer',193          args: {194            from: owner,195            to: '0x0000000000000000000000000000000000000000',196            tokenId: tokenId.toString(),197          },198        },199      ]);200    }201  });202203  itWeb3('Can perform approve()', async ({ web3, api }) => {204    const collection = await createCollectionExpectSuccess({205      mode: { type: 'NFT' },206    });207    const alice = privateKey('//Alice');208209    const owner = createEthAccount(web3);210    await transferBalanceToEth(api, alice, owner, 999999999999999);211212    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });213214    const spender = createEthAccount(web3);215216    const address = collectionIdToAddress(collection);217    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);218219    {220      const result = await contract.methods.approve(spender, tokenId).send({ from: owner, gas: '0x1000000', gasPrice: '0x01' });221      const events = normalizeEvents(result.events);222223      expect(events).to.be.deep.equal([224        {225          address,226          event: 'Approval',227          args: {228            owner,229            approved: spender,230            tokenId: tokenId.toString(),231          },232        },233      ]);234    }235  });236237  itWeb3('Can perform transferFrom()', async ({ web3, api }) => {238    const collection = await createCollectionExpectSuccess({239      mode: { type: 'NFT' },240    });241    const alice = privateKey('//Alice');242243    const owner = createEthAccount(web3);244    await transferBalanceToEth(api, alice, owner, 999999999999999);245246    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });247248    const spender = createEthAccount(web3);249    await transferBalanceToEth(api, alice, spender, 999999999999999);250251    const receiver = createEthAccount(web3);252253    const address = collectionIdToAddress(collection);254    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});255256    await contract.methods.approve(spender, tokenId).send({ from: owner });257258    {259      const result = await contract.methods.transferFrom(owner, receiver, tokenId).send({ from: spender });260      const events = normalizeEvents(result.events);261      expect(events).to.be.deep.equal([262        {263          address,264          event: 'Transfer',265          args: {266            from: owner,267            to: receiver,268            tokenId: tokenId.toString(),269          },270        },271      ]);272    }273274    {275      const balance = await contract.methods.balanceOf(receiver).call();276      expect(+balance).to.equal(1);277    }278279    {280      const balance = await contract.methods.balanceOf(owner).call();281      expect(+balance).to.equal(0);282    }283  });284285  itWeb3('Can perform transfer()', async ({ web3, api }) => {286    const collection = await createCollectionExpectSuccess({287      mode: { type: 'NFT' },288    });289    const alice = privateKey('//Alice');290291    const owner = createEthAccount(web3);292    await transferBalanceToEth(api, alice, owner, 999999999999999);293294    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });295296    const receiver = createEthAccount(web3);297    await transferBalanceToEth(api, alice, receiver, 999999999999999);298299    const address = collectionIdToAddress(collection);300    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});301302    {303      const result = await contract.methods.transfer(receiver, tokenId).send({ from: owner });304      await waitNewBlocks(api, 1);305      const events = normalizeEvents(result.events);306      expect(events).to.be.deep.equal([307        {308          address,309          event: 'Transfer',310          args: {311            from: owner,312            to: receiver,313            tokenId: tokenId.toString(),314          },315        },316      ]);317    }318319    {320      const balance = await contract.methods.balanceOf(owner).call();321      expect(+balance).to.equal(0);322    }323324    {325      const balance = await contract.methods.balanceOf(receiver).call();326      expect(+balance).to.equal(1);327    }328  });329330  itWeb3('Can perform getVariableMetadata', async ({ web3, api }) => {331    const collection = await createCollectionExpectSuccess({332      mode: { type: 'NFT' },333    });334    const alice = privateKey('//Alice');335336    const owner = await createEthAccountWithBalance(api, web3);337338    const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });339    await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);340341    const address = collectionIdToAddress(collection);342    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });343    344    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');345  });346347  itWeb3('Can perform setVariableMetadata', async ({ web3, api }) => {348    const collection = await createCollectionExpectSuccess({349      mode: { type: 'NFT' },350    });351    const alice = privateKey('//Alice');352353    const owner = await createEthAccountWithBalance(api, web3);354355    const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });356357    const address = collectionIdToAddress(collection);358    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });359    360    expect(await contract.methods.setVariableMetadata(item, '0x010203').send({ from: owner }));361    await waitNewBlocks(api, 1);362    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');363  });364});365366describe('NFT: Fees', () => {367  itWeb3('approve() call fee is less than 0.2UNQ', async ({ web3, api }) => {368    const collection = await createCollectionExpectSuccess({369      mode: { type: 'NFT' },370    });371    const alice = privateKey('//Alice');372373    const owner = await createEthAccountWithBalance(api, web3);374    const spender = createEthAccount(web3);375376    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });377378    const address = collectionIdToAddress(collection);379    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });380381    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, tokenId).send({ from: owner }));382    expect(cost < BigInt(0.2 * Number(UNIQUE)));383  });384385  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({ web3, api }) => {386    const collection = await createCollectionExpectSuccess({387      mode: { type: 'NFT' },388    });389    const alice = privateKey('//Alice');390  391    const owner = await createEthAccountWithBalance(api, web3);392    const spender = await createEthAccountWithBalance(api, web3);393394    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });395396    const address = collectionIdToAddress(collection);397    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });398399    await contract.methods.approve(spender, tokenId).send({ from: owner });400401    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, tokenId).send({ from: spender }));402    expect(cost < BigInt(0.2 * Number(UNIQUE)));403  });404405  itWeb3('transfer() call fee is less than 0.2UNQ', async ({ web3, api }) => {406    const collection = await createCollectionExpectSuccess({407      mode: { type: 'NFT' },408    });409    const alice = privateKey('//Alice');410411    const owner = await createEthAccountWithBalance(api, web3);412    const receiver = createEthAccount(web3);413414    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: owner });415416    const address = collectionIdToAddress(collection);417    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, { from: owner, ...GAS_ARGS });418419    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, tokenId).send({ from: owner }));420    expect(cost < BigInt(0.2 * Number(UNIQUE)));421  });422});423424describe('NFT: Substrate calls', () => {425  itWeb3('Events emitted for mint()', async ({ web3 }) => {426    const collection = await createCollectionExpectSuccess({427      mode: { type: 'NFT' },428    });429    const alice = privateKey('//Alice');430431    const address = collectionIdToAddress(collection);432    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);433434    let tokenId: number;435    const events = await recordEvents(contract, async () => {436      tokenId = await createItemExpectSuccess(alice, collection, 'NFT');437    });438439    expect(events).to.be.deep.equal([440      {441        address,442        event: 'Transfer',443        args: {444          from: '0x0000000000000000000000000000000000000000',445          to: subToEth(alice.address),446          tokenId: tokenId!.toString(),447        },448      },449    ]);450  });451452  itWeb3('Events emitted for burn()', async ({ web3 }) => {453    const collection = await createCollectionExpectSuccess({454      mode: { type: 'NFT' },455    });456    const alice = privateKey('//Alice');457458    const address = collectionIdToAddress(collection);459    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);460461    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');462    const events = await recordEvents(contract, async () => {463      await burnItemExpectSuccess(alice, collection, tokenId);464    });465466    expect(events).to.be.deep.equal([467      {468        address,469        event: 'Transfer',470        args: {471          from: subToEth(alice.address),472          to: '0x0000000000000000000000000000000000000000',473          tokenId: tokenId.toString(),474        },475      },476    ]);477  });478479  itWeb3('Events emitted for approve()', async ({ web3 }) => {480    const collection = await createCollectionExpectSuccess({481      mode: { type: 'NFT' },482    });483    const alice = privateKey('//Alice');484485    const receiver = createEthAccount(web3);486487    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');488489    const address = collectionIdToAddress(collection);490    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);491492    const events = await recordEvents(contract, async () => {493      await approveExpectSuccess(collection, tokenId, alice, { ethereum: receiver }, 1);494    });495496    expect(events).to.be.deep.equal([497      {498        address,499        event: 'Approval',500        args: {501          owner: subToEth(alice.address),502          approved: receiver,503          tokenId: tokenId.toString(),504        },505      },506    ]);507  });508509  itWeb3('Events emitted for transferFrom()', async ({ web3 }) => {510    const collection = await createCollectionExpectSuccess({511      mode: { type: 'NFT' },512    });513    const alice = privateKey('//Alice');514    const bob = privateKey('//Bob');515516    const receiver = createEthAccount(web3);517518    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');519    await approveExpectSuccess(collection, tokenId, alice, bob, 1);520521    const address = collectionIdToAddress(collection);522    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);523524    const events = await recordEvents(contract, async () => {525      await transferFromExpectSuccess(collection, tokenId, bob, alice, { ethereum: receiver }, 1, 'NFT');526    });527528    expect(events).to.be.deep.equal([529      {530        address,531        event: 'Transfer',532        args: {533          from: subToEth(alice.address),534          to: receiver,535          tokenId: tokenId.toString(),536        },537      },538    ]);539  });540541  itWeb3('Events emitted for transfer()', async ({ web3 }) => {542    const collection = await createCollectionExpectSuccess({543      mode: { type: 'NFT' },544    });545    const alice = privateKey('//Alice');546547    const receiver = createEthAccount(web3);548549    const tokenId = await createItemExpectSuccess(alice, collection, 'NFT');550551    const address = collectionIdToAddress(collection);552    const contract = new web3.eth.Contract(nonFungibleAbi as any, address);553554    const events = await recordEvents(contract, async () => {555      await transferExpectSuccess(collection, tokenId, alice, { ethereum: receiver }, 1, 'NFT');556    });557558    expect(events).to.be.deep.equal([559      {560        address,561        event: 'Transfer',562        args: {563          from: subToEth(alice.address),564          to: receiver,565          tokenId: tokenId.toString(),566        },567      },568    ]);569  });570});
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -50,7 +50,7 @@
         "type": "event"
     },
     {
-        "anonymous": true,
+        "anonymous": false,
         "inputs": [],
         "name": "MintingFinished",
         "type": "event"
@@ -165,6 +165,25 @@
     {
         "inputs": [
             {
+                "internalType": "uint256",
+                "name": "tokenId",
+                "type": "uint256"
+            }
+        ],
+        "name": "getVariableMetadata",
+        "outputs": [
+            {
+                "internalType": "bytes",
+                "name": "",
+                "type": "bytes"
+            }
+        ],
+        "stateMutability": "view",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
                 "internalType": "address",
                 "name": "owner",
                 "type": "address"
@@ -218,13 +237,73 @@
                 "type": "address"
             },
             {
+                "internalType": "uint256[]",
+                "name": "tokenIds",
+                "type": "uint256[]"
+            }
+        ],
+        "name": "mintBulk",
+        "outputs": [
+            {
+                "internalType": "bool",
+                "name": "",
+                "type": "bool"
+            }
+        ],
+        "stateMutability": "nonpayable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
+                "internalType": "address",
+                "name": "to",
+                "type": "address"
+            },
+            {
+                "components": [
+                    {
+                        "internalType": "uint256",
+                        "name": "field_0",
+                        "type": "uint256"
+                    },
+                    {
+                        "internalType": "string",
+                        "name": "field_1",
+                        "type": "string"
+                    }
+                ],
+                "internalType": "struct Tuple0[]",
+                "name": "tokens",
+                "type": "tuple[]"
+            }
+        ],
+        "name": "mintBulkWithTokenURI",
+        "outputs": [
+            {
+                "internalType": "bool",
+                "name": "",
+                "type": "bool"
+            }
+        ],
+        "stateMutability": "nonpayable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
+                "internalType": "address",
+                "name": "to",
+                "type": "address"
+            },
+            {
                 "internalType": "uint256",
                 "name": "tokenId",
                 "type": "uint256"
             },
             {
                 "internalType": "string",
-                "name": "tokenURI",
+                "name": "tokenUri",
                 "type": "string"
             }
         ],
@@ -369,6 +448,24 @@
     {
         "inputs": [
             {
+                "internalType": "uint256",
+                "name": "tokenId",
+                "type": "uint256"
+            },
+            {
+                "internalType": "bytes",
+                "name": "data",
+                "type": "bytes"
+            }
+        ],
+        "name": "setVariableMetadata",
+        "outputs": [],
+        "stateMutability": "nonpayable",
+        "type": "function"
+    },
+    {
+        "inputs": [
+            {
                 "internalType": "uint32",
                 "name": "interfaceId",
                 "type": "uint32"
@@ -514,4 +611,4 @@
         "stateMutability": "nonpayable",
         "type": "function"
     }
-]
\ No newline at end of file
+]