git.delta.rocks / unique-network / refs/commits / 88feb2174f9b

difftreelog

test bulkMint/metadata via proxy

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

6 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, 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/proxy/UniqueNFTProxy.abidiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.abi
+++ b/tests/src/eth/proxy/UniqueNFTProxy.abi
@@ -1 +1 @@
-[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","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","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"interfaceId","type":"uint32"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
+[{"inputs":[{"internalType":"address","name":"_proxied","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"MintingFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finishMinting","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"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"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","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","type":"string"}],"name":"mintWithTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingFinished","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFromWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"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"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
modifiedtests/src/eth/proxy/UniqueNFTProxy.bindiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.bin
+++ b/tests/src/eth/proxy/UniqueNFTProxy.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b506040516111e03803806111e083398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61114d806100936000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806350bb4e7f116100c357806395d89b411161007c57806395d89b41146102a8578063a22cb465146102b0578063a9059cbb146102c3578063c87b56dd146102d6578063e985e9c5146102e9578063f4f4b500146102fc57600080fd5b806350bb4e7f1461024c57806360a116721461025f5780636352211e1461027257806370a082311461028557806375794a3c146102985780637d64bcb4146102a057600080fd5b806323b872dd1161011557806323b872dd146101da5780632f745c59146101ed57806340c10f191461020057806342842e0e1461021357806342966c68146102265780634f6ccce71461023957600080fd5b806305d2035b1461015257806306fdde031461016f578063081812fc14610184578063095ea7b3146101af57806318160ddd146101c4575b600080fd5b61015a61030f565b60405190151581526020015b60405180910390f35b61017761039b565b6040516101669190611043565b610197610192366004610f5b565b61041b565b6040516001600160a01b039091168152602001610166565b6101c26101bd366004610e2e565b61049f565b005b6101cc61050a565b604051908152602001610166565b6101c26101e8366004610d3f565b610591565b6101cc6101fb366004610e2e565b610605565b61015a61020e366004610e2e565b610691565b6101c2610221366004610d3f565b610718565b6101c2610234366004610f5b565b610759565b6101cc610247366004610f5b565b6107ba565b61015a61025a366004610e5a565b610838565b6101c261026d366004610d80565b6108c7565b610197610280366004610f5b565b610936565b6101cc610293366004610ccc565b610968565b6101cc61099b565b61015a6109ea565b610177610a4f565b6101c26102be366004610e00565b610a93565b6101c26102d1366004610e2e565b610acd565b6101776102e4366004610f5b565b610b06565b6101976102f7366004610d06565b610b87565b61015a61030a366004610f8d565b610c0d565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561035e57600080fd5b505afa158015610372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103969190610ec7565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526103969190810190610ee4565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b60206040518083038186803b15801561046157600080fd5b505afa158015610475573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610ce9565b92915050565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561055957600080fd5b505afa15801561056d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103969190610f74565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b1580156105e857600080fd5b505af11580156105fc573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c599060440160206040518083038186803b15801561065257600080fd5b505afa158015610666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610f74565b9392505050565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f1990604401602060405180830381600087803b1580156106e057600080fd5b505af11580156106f4573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610ec7565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e906064016105ce565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561079f57600080fd5b505af11580156107b3573d6000803e3d6000fd5b5050505050565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b60206040518083038186803b15801561080057600080fd5b505afa158015610814573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610f74565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f9061086d9087908790879060040161101c565b602060405180830381600087803b15801561088757600080fd5b505af115801561089b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108bf9190610ec7565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a11672906108fd908790879087908790600401610fdf565b600060405180830381600087803b15801561091757600080fd5b505af115801561092b573d6000803e3d6000fd5b505050505b50505050565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e90602401610449565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a08231906024016107e8565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561055957600080fd5b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610a3b57600080fd5b505af1158015610372573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b1580156103df57600080fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb465906044016104d4565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016104d4565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd9060240160006040518083038186803b158015610b4b57600080fd5b505afa158015610b5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104999190810190610ee4565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c59060440160206040518083038186803b158015610bd557600080fd5b505afa158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190610ce9565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b158015610c5657600080fd5b505afa158015610c6a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104999190610ec7565b6000610ca1610c9c84611087565b611056565b9050828152838383011115610cb557600080fd5b828260208301376000602084830101529392505050565b600060208284031215610cde57600080fd5b813561068a816110f1565b600060208284031215610cfb57600080fd5b815161068a816110f1565b60008060408385031215610d1957600080fd5b8235610d24816110f1565b91506020830135610d34816110f1565b809150509250929050565b600080600060608486031215610d5457600080fd5b8335610d5f816110f1565b92506020840135610d6f816110f1565b929592945050506040919091013590565b60008060008060808587031215610d9657600080fd5b8435610da1816110f1565b93506020850135610db1816110f1565b925060408501359150606085013567ffffffffffffffff811115610dd457600080fd5b8501601f81018713610de557600080fd5b610df487823560208401610c8e565b91505092959194509250565b60008060408385031215610e1357600080fd5b8235610e1e816110f1565b91506020830135610d3481611109565b60008060408385031215610e4157600080fd5b8235610e4c816110f1565b946020939093013593505050565b600080600060608486031215610e6f57600080fd5b8335610e7a816110f1565b925060208401359150604084013567ffffffffffffffff811115610e9d57600080fd5b8401601f81018613610eae57600080fd5b610ebd86823560208401610c8e565b9150509250925092565b600060208284031215610ed957600080fd5b815161068a81611109565b600060208284031215610ef657600080fd5b815167ffffffffffffffff811115610f0d57600080fd5b8201601f81018413610f1e57600080fd5b8051610f2c610c9c82611087565b818152856020838501011115610f4157600080fd5b610f528260208301602086016110af565b95945050505050565b600060208284031215610f6d57600080fd5b5035919050565b600060208284031215610f8657600080fd5b5051919050565b600060208284031215610f9f57600080fd5b813563ffffffff8116811461068a57600080fd5b60008151808452610fcb8160208601602086016110af565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061101290830184610fb3565b9695505050505050565b60018060a01b0384168152826020820152606060408201526000610f526060830184610fb3565b60208152600061068a6020830184610fb3565b604051601f8201601f1916810167ffffffffffffffff8111828210171561107f5761107f6110db565b604052919050565b600067ffffffffffffffff8211156110a1576110a16110db565b50601f01601f191660200190565b60005b838110156110ca5781810151838201526020016110b2565b838111156109305750506000910152565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461110657600080fd5b50565b801515811461110657600080fdfea2646970667358221220cd50bb20b48b73eddb390585af8699a01cd5f49b79ab50aa532df41df639f36764736f6c63430008070033
\ No newline at end of file
+608060405234801561001057600080fd5b5060405161168d38038061168d83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b6115fa806100936000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c806350bb4e7f116100f9578063a22cb46511610097578063d4eac26d11610071578063d4eac26d1461036b578063e6c5ce6f1461037e578063e985e9c514610391578063f4f4b500146103a457600080fd5b8063a22cb46514610332578063a9059cbb14610345578063c87b56dd1461035857600080fd5b806370a08231116100d357806370a082311461030757806375794a3c1461031a5780637d64bcb41461032257806395d89b411461032a57600080fd5b806350bb4e7f146102ce57806360a11672146102e15780636352211e146102f457600080fd5b80632f745c591161016657806342842e0e1161014057806342842e0e1461028257806342966c681461029557806344a9945e146102a85780634f6ccce7146102bb57600080fd5b80632f745c5914610249578063365430061461025c57806340c10f191461026f57600080fd5b806305d2035b146101ae57806306fdde03146101cb578063081812fc146101e0578063095ea7b31461020b57806318160ddd1461022057806323b872dd14610236575b600080fd5b6101b66103b7565b60405190151581526020015b60405180910390f35b6101d3610443565b6040516101c2919061148a565b6101f36101ee366004611277565b6104c3565b6040516001600160a01b0390911681526020016101c2565b61021e61021936600461118c565b610547565b005b6102286105b2565b6040519081526020016101c2565b61021e610244366004610eff565b610639565b61022861025736600461118c565b6106ad565b6101b661026a366004610fac565b610739565b6101b661027d36600461118c565b6107be565b61021e610290366004610eff565b6107f8565b61021e6102a3366004611277565b610839565b6101b66102b63660046110b1565b61089a565b6102286102c9366004611277565b6108cd565b6101b66102dc3660046111b8565b61094b565b61021e6102ef366004610f40565b6109da565b6101f3610302366004611277565b610a49565b610228610315366004610e8c565b610a7b565b610228610aae565b6101b6610afd565b6101d3610b62565b61021e61034036600461115e565b610ba6565b61021e61035336600461118c565b610be0565b6101d3610366366004611277565b610c19565b61021e6103793660046112a9565b610c9b565b6101d361038c366004611277565b610ccd565b6101f361039f366004610ec6565b610cff565b6101b66103b23660046112f0565b610d85565b60008060009054906101000a90046001600160a01b03166001600160a01b03166305d2035b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561040657600080fd5b505afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611211565b905090565b60008054604080516306fdde0360e01b815290516060936001600160a01b03909316926306fdde039260048082019391829003018186803b15801561048757600080fd5b505afa15801561049b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261043e919081019061122e565b6000805460405163020604bf60e21b8152600481018490526001600160a01b039091169063081812fc906024015b60206040518083038186803b15801561050957600080fd5b505afa15801561051d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190610ea9565b92915050565b60005460405163095ea7b360e01b81526001600160a01b038481166004830152602482018490529091169063095ea7b3906044015b600060405180830381600087803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b505afa158015610615573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e9190611290565b6000546040516323b872dd60e01b81526001600160a01b038581166004830152848116602483015260448201849052909116906323b872dd906064015b600060405180830381600087803b15801561069057600080fd5b505af11580156106a4573d6000803e3d6000fd5b50505050505050565b60008054604051632f745c5960e01b81526001600160a01b0385811660048301526024820185905290911690632f745c599060440160206040518083038186803b1580156106fa57600080fd5b505afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611290565b9392505050565b60008054604051631b2a180360e11b81526001600160a01b039091169063365430069061076c908690869060040161137f565b602060405180830381600087803b15801561078657600080fd5b505af115801561079a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190611211565b600080546040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052909116906340c10f199060440161076c565b600054604051632142170760e11b81526001600160a01b038581166004830152848116602483015260448201849052909116906342842e0e90606401610676565b600054604051630852cd8d60e31b8152600481018390526001600160a01b03909116906342966c6890602401600060405180830381600087803b15801561087f57600080fd5b505af1158015610893573d6000803e3d6000fd5b5050505050565b60008054604051632254ca2f60e11b81526001600160a01b03909116906344a9945e9061076c9086908690600401611404565b60008054604051634f6ccce760e01b8152600481018490526001600160a01b0390911690634f6ccce7906024015b60206040518083038186803b15801561091357600080fd5b505afa158015610927573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611290565b600080546040516350bb4e7f60e01b81526001600160a01b03909116906350bb4e7f906109809087908790879060040161145a565b602060405180830381600087803b15801561099a57600080fd5b505af11580156109ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d29190611211565b949350505050565b6000546040516330508b3960e11b81526001600160a01b03909116906360a1167290610a10908790879087908790600401611342565b600060405180830381600087803b158015610a2a57600080fd5b505af1158015610a3e573d6000803e3d6000fd5b505050505b50505050565b600080546040516331a9108f60e11b8152600481018490526001600160a01b0390911690636352211e906024016104f1565b600080546040516370a0823160e01b81526001600160a01b038481166004830152909116906370a08231906024016108fb565b60008060009054906101000a90046001600160a01b03166001600160a01b03166375794a3c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561060157600080fd5b60008060009054906101000a90046001600160a01b03166001600160a01b0316637d64bcb46040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610b4e57600080fd5b505af115801561041a573d6000803e3d6000fd5b60008054604080516395d89b4160e01b815290516060936001600160a01b03909316926395d89b419260048082019391829003018186803b15801561048757600080fd5b60005460405163a22cb46560e01b81526001600160a01b03848116600483015283151560248301529091169063a22cb4659060440161057c565b60005460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb9060440161057c565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd906024015b60006040518083038186803b158015610c5f57600080fd5b505afa158015610c73573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610541919081019061122e565b60005460405163d4eac26d60e01b81526001600160a01b039091169063d4eac26d9061057c908590859060040161149d565b60005460405163e6c5ce6f60e01b8152600481018390526060916001600160a01b03169063e6c5ce6f90602401610c47565b6000805460405163e985e9c560e01b81526001600160a01b03858116600483015284811660248301529091169063e985e9c59060440160206040518083038186803b158015610d4d57600080fd5b505afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107329190610ea9565b6000805460405162f4f4b560e81b815263ffffffff841660048201526001600160a01b039091169063f4f4b5009060240160206040518083038186803b158015610dce57600080fd5b505afa158015610de2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105419190611211565b6000610e19610e1484611534565b6114df565b9050828152838383011115610e2d57600080fd5b61073283602083018461155c565b600082601f830112610e4c57600080fd5b8135610e5a610e1482611534565b818152846020838601011115610e6f57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610e9e57600080fd5b81356107328161159e565b600060208284031215610ebb57600080fd5b81516107328161159e565b60008060408385031215610ed957600080fd5b8235610ee48161159e565b91506020830135610ef48161159e565b809150509250929050565b600080600060608486031215610f1457600080fd5b8335610f1f8161159e565b92506020840135610f2f8161159e565b929592945050506040919091013590565b60008060008060808587031215610f5657600080fd5b8435610f618161159e565b93506020850135610f718161159e565b925060408501359150606085013567ffffffffffffffff811115610f9457600080fd5b610fa087828801610e3b565b91505092959194509250565b60008060408385031215610fbf57600080fd5b8235610fca8161159e565b915060208381013567ffffffffffffffff80821115610fe857600080fd5b818601915086601f830112610ffc57600080fd5b813561100a610e1482611510565b8082825285820191508585018a878560051b880101111561102a57600080fd5b60005b848110156110a05781358681111561104457600080fd5b87016040818e03601f1901121561105a57600080fd5b6110626114b6565b89820135815260408201358881111561107a57600080fd5b6110888f8c83860101610e3b565b828c015250855250928701929087019060010161102d565b50979a909950975050505050505050565b600080604083850312156110c457600080fd5b82356110cf8161159e565b915060208381013567ffffffffffffffff8111156110ec57600080fd5b8401601f810186136110fd57600080fd5b803561110b610e1482611510565b80828252848201915084840189868560051b870101111561112b57600080fd5b600094505b8385101561114e578035835260019490940193918501918501611130565b5080955050505050509250929050565b6000806040838503121561117157600080fd5b823561117c8161159e565b91506020830135610ef4816115b6565b6000806040838503121561119f57600080fd5b82356111aa8161159e565b946020939093013593505050565b6000806000606084860312156111cd57600080fd5b83356111d88161159e565b925060208401359150604084013567ffffffffffffffff8111156111fb57600080fd5b61120786828701610e3b565b9150509250925092565b60006020828403121561122357600080fd5b8151610732816115b6565b60006020828403121561124057600080fd5b815167ffffffffffffffff81111561125757600080fd5b8201601f8101841361126857600080fd5b6109d284825160208401610e06565b60006020828403121561128957600080fd5b5035919050565b6000602082840312156112a257600080fd5b5051919050565b600080604083850312156112bc57600080fd5b82359150602083013567ffffffffffffffff8111156112da57600080fd5b6112e685828601610e3b565b9150509250929050565b60006020828403121561130257600080fd5b813563ffffffff8116811461073257600080fd5b6000815180845261132e81602086016020860161155c565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061137590830184611316565b9695505050505050565b6001600160a01b0383168152604060208083018290528351828401819052600092916060600583901b860181019290860190878301865b828110156113f557888603605f190184528151805187528501518587018890526113e288880182611316565b96505092840192908401906001016113b6565b50939998505050505050505050565b6001600160a01b038316815260406020808301829052835191830182905260009184820191906060850190845b8181101561144d57845183529383019391830191600101611431565b5090979650505050505050565b60018060a01b03841681528260208201526060604082015260006114816060830184611316565b95945050505050565b6020815260006107326020830184611316565b8281526040602082015260006109d26040830184611316565b6040805190810167ffffffffffffffff811182821017156114d9576114d9611588565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561150857611508611588565b604052919050565b600067ffffffffffffffff82111561152a5761152a611588565b5060051b60200190565b600067ffffffffffffffff82111561154e5761154e611588565b50601f01601f191660200190565b60005b8381101561157757818101518382015260200161155f565b83811115610a435750506000910152565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146115b357600080fd5b50565b80151581146115b357600080fdfea2646970667358221220669a75a3efcdc6b60606caa5c7e41cab1d727e89a03fd231d1cda27f4de159a064736f6c63430008070033
\ No newline at end of file
modifiedtests/src/eth/proxy/UniqueNFTProxy.soldiffbeforeafterboth
--- a/tests/src/eth/proxy/UniqueNFTProxy.sol
+++ b/tests/src/eth/proxy/UniqueNFTProxy.sol
@@ -156,4 +156,36 @@
     {
         return proxied.supportsInterface(interfaceId);
     }
+
+    function setVariableMetadata(uint256 tokenId, bytes memory data)
+        external
+        override
+    {
+        return proxied.setVariableMetadata(tokenId, data);
+    }
+
+    function getVariableMetadata(uint256 tokenId)
+        external
+        view
+        override
+        returns (bytes memory)
+    {
+        return proxied.getVariableMetadata(tokenId);
+    }
+
+    function mintBulk(address to, uint256[] memory tokenIds)
+        external
+        override
+        returns (bool)
+    {
+        return proxied.mintBulk(to, tokenIds);
+    }
+
+    function mintBulkWithTokenURI(address to, Tuple0[] memory tokens)
+        external
+        override
+        returns (bool)
+    {
+        return proxied.mintBulkWithTokenURI(to, tokens);
+    }
 }
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -4,7 +4,7 @@
 //
 
 import privateKey from '../../substrate/privateKey';
-import { createCollectionExpectSuccess, createItemExpectSuccess } from '../../util/helpers';
+import { createCollectionExpectSuccess, createItemExpectSuccess, setVariableMetaDataExpectSuccess } from '../../util/helpers';
 import { collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents } from '../util/helpers';
 import nonFungibleAbi from '../nonFungibleAbi.json';
 import { expect } from 'chai';
@@ -96,13 +96,11 @@
     {
       const nextTokenId = await contract.methods.nextTokenId().call();
       expect(nextTokenId).to.be.equal('1');
-      console.log('Before mint');
       const result = await contract.methods.mintWithTokenURI(
         receiver,
         nextTokenId,
         'Test URI',
       ).send({ from: caller });
-      console.log('After mint');
       const events = normalizeEvents(result.events);
 
       expect(events).to.be.deep.equal([
@@ -121,6 +119,69 @@
       expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');
     }
   });
+  itWeb3('Can perform mintBulk()', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+
+    const caller = await createEthAccountWithBalance(api, web3);
+    const receiver = createEthAccount(web3);
+
+    const address = collectionIdToAddress(collection);
+    const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));
+    const changeAdminTx = api.tx.nft.addCollectionAdmin(collection, { ethereum: contract.options.address });
+    await submitTransactionAsync(alice, changeAdminTx);
+
+    {
+      const nextTokenId = await contract.methods.nextTokenId().call();
+      expect(nextTokenId).to.be.equal('1');
+      const result = await contract.methods.mintBulkWithTokenURI(
+        receiver,
+        [
+          [nextTokenId, 'Test URI 0'],
+          [+nextTokenId + 1, 'Test URI 1'],
+          [+nextTokenId + 2, 'Test URI 2'],
+        ],
+      ).send({ from: caller });
+      const events = normalizeEvents(result.events);
+
+      expect(events).to.be.deep.equal([
+        {
+          address,
+          event: 'Transfer',
+          args: {
+            from: '0x0000000000000000000000000000000000000000',
+            to: receiver,
+            tokenId: nextTokenId,
+          },
+        },
+        {
+          address,
+          event: 'Transfer',
+          args: {
+            from: '0x0000000000000000000000000000000000000000',
+            to: receiver,
+            tokenId: String(+nextTokenId + 1),
+          },
+        },
+        {
+          address,
+          event: 'Transfer',
+          args: {
+            from: '0x0000000000000000000000000000000000000000',
+            to: receiver,
+            tokenId: String(+nextTokenId + 2),
+          },
+        },
+      ]);
+
+      await waitNewBlocks(api, 1);
+      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI 0');
+      expect(await contract.methods.tokenURI(+nextTokenId + 1).call()).to.be.equal('Test URI 1');
+      expect(await contract.methods.tokenURI(+nextTokenId + 2).call()).to.be.equal('Test URI 2');
+    }
+  });
 
   itWeb3('Can perform burn()', async ({ web3, api }) => {
     const collection = await createCollectionExpectSuccess({
@@ -267,4 +328,35 @@
       expect(+balance).to.equal(1);
     }
   });
+
+  itWeb3('Can perform getVariableMetadata', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+
+    const address = collectionIdToAddress(collection);
+    const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));
+    const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: contract.options.address });
+    await setVariableMetaDataExpectSuccess(alice, collection, item, [1, 2, 3]);
+    
+    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
+  });
+
+  itWeb3('Can perform setVariableMetadata', async ({ web3, api }) => {
+    const collection = await createCollectionExpectSuccess({
+      mode: { type: 'NFT' },
+    });
+    const alice = privateKey('//Alice');
+    const caller = await createEthAccountWithBalance(api, web3);
+
+    const address = collectionIdToAddress(collection);
+    const contract = await proxyWrap(api, web3, new web3.eth.Contract(nonFungibleAbi as any, address, { from: caller, ...GAS_ARGS }));
+    const item = await createItemExpectSuccess(alice, collection, 'NFT', { ethereum: contract.options.address });
+    
+    expect(await contract.methods.setVariableMetadata(item, '0x010203').send({ from: caller }));
+    await waitNewBlocks(api, 1);
+    expect(await contract.methods.getVariableMetadata(item).call()).to.be.equal('0x010203');
+  });
 });
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -269,4 +269,4 @@
   expect(after < before).to.be.true;
 
   return before - after;
-}
\ No newline at end of file
+}