--- a/tests/src/eth/base.test.ts +++ b/tests/src/eth/base.test.ts @@ -23,7 +23,7 @@ describe('Contract calls', () => { let donor: IKeyringPair; - before(async function() { + before(async function () { await usingEthPlaygrounds(async (_helper, privateKey) => { donor = privateKey('//Alice'); }); @@ -40,7 +40,12 @@ itEth('Balance transfer fee is less than 0.2 UNQ', async ({helper}) => { const userA = await helper.eth.createAccountWithBalance(donor); const userB = helper.eth.createAccount(); - const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({from: userA, to: userB, value: '1000000', gas: helper.eth.DEFAULT_GAS})); + const cost = await helper.eth.calculateFee({Ethereum: userA}, () => helper.getWeb3().eth.sendTransaction({ + from: userA, + to: userB, + value: '1000000', + gas: helper.eth.DEFAULT_GAS + })); const balanceB = await helper.balance.getEthereum(userB); expect(cost - balanceB < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))).to.be.true; }); @@ -69,67 +74,59 @@ describe('ERC165 tests', async () => { // https://eips.ethereum.org/EIPS/eip-165 - let collection: number; + let erc721MetadataCompatibleNftCollectionId: number; + let simpleNftCollectionId: number; let minter: string; - function contract(helper: EthUniqueHelper): Contract { - return helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection), 'nft', minter); + const BASE_URI = 'base/'; + + async function checkInterface(helper: EthUniqueHelper, interfaceId: string, simpleResult: boolean, compatibleResult: boolean) { + const simple = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter); + const compatible = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter); + + expect(await simple.methods.supportsInterface(interfaceId).call()).to.equal(simpleResult, `empty (not ERC721Metadata compatible) NFT collection returns not ${simpleResult}`); + expect(await compatible.methods.supportsInterface(interfaceId).call()).to.equal(compatibleResult, `ERC721Metadata compatible NFT collection returns not ${compatibleResult}`); } before(async () => { await usingEthPlaygrounds(async (helper, privateKey) => { const donor = privateKey('//Alice'); - const [alice] = await helper.arrange.createAccounts([10n], donor); - ({collectionId: collection} = await helper.nft.mintCollection( - alice, - { - name: 'test', - description: 'test', - tokenPrefix: 'test', - properties: [{key: 'ERC721Metadata', value: '1'}], - tokenPropertyPermissions: [{ - key: 'URI', - permission: { - mutable: true, - collectionAdmin: true, - tokenOwner: false, - }, - }], - }, - )); - minter = helper.eth.createAccount(); + minter = await helper.eth.createAccountWithBalance(donor); + + simpleNftCollectionId = (await helper.eth.createNFTCollection(minter, 'n', 'd', 'p')).collectionId; + erc721MetadataCompatibleNftCollectionId = (await helper.eth.createERC721MetadataCompatibleNFTCollection(minter, 'n', 'd', 'p', BASE_URI)).collectionId; }); }); - itEth('interfaceID == 0xffffffff always false', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0xffffffff').call()).to.be.false; + itEth('nonexistent interfaceID - 0xffffffff - always false', async ({helper}) => { + await checkInterface(helper, '0xffffffff', false, false); }); - itEth('ERC721 support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x780e9d63').call()).to.be.true; + itEth('ERC721 - 0x780e9d63 - support', async ({helper}) => { + await checkInterface(helper, '0x780e9d63', true, true); }); - itEth('ERC721Metadata support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x5b5e139f').call()).to.be.true; + itEth('ERC721Metadata - 0x5b5e139f - support', async ({helper}) => { + await checkInterface(helper, '0x5b5e139f', false, true); }); - itEth('ERC721Mintable support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x68ccfe89').call()).to.be.true; + itEth('ERC721UniqueMintable - 0x476ff149 - support', async ({helper}) => { + await checkInterface(helper, '0x476ff149', true, true); }); - itEth('ERC721Enumerable support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x780e9d63').call()).to.be.true; + itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => { + await checkInterface(helper, '0x780e9d63', true, true); }); - itEth('ERC721UniqueExtensions support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0xd74d154f').call()).to.be.true; + itEth('ERC721UniqueExtensions - 0x4468500d - support', async ({helper}) => { + await checkInterface(helper, '0x4468500d', true, true); }); - itEth('ERC721Burnable support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x42966c68').call()).to.be.true; + itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => { + await checkInterface(helper, '0x42966c68', true, true); }); - itEth('ERC165 support', async ({helper}) => { - expect(await contract(helper).methods.supportsInterface('0x01ffc9a7').call()).to.be.true; + itEth('ERC165 - 0x01ffc9a7 - support', async ({helper}) => { + await checkInterface(helper, '0x01ffc9a7', true, true); }); }); --- a/tests/src/eth/collectionProperties.test.ts +++ b/tests/src/eth/collectionProperties.test.ts @@ -1,6 +1,7 @@ -import {itEth, usingEthPlaygrounds, expect} from './util/playgrounds'; +import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util/playgrounds'; import {IKeyringPair} from '@polkadot/types/types'; import {Pallets} from '../util/playgrounds'; +import {IProperty, ITokenPropertyPermission} from "../util/playgrounds/types"; describe('EVM collection properties', () => { let donor: IKeyringPair; @@ -65,52 +66,82 @@ }); }); - itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => { + const checkERC721Metadata = async (helper: EthUniqueHelper, mode: 'nft' | 'rft') => { const caller = await helper.eth.createAccountWithBalance(donor); - const tokenPropertyPermissions = [{ - key: 'URI', - permission: { - mutable: true, - collectionAdmin: true, - tokenOwner: false, - }, - }]; - const collection = await helper.nft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions}); + const bruh = await helper.eth.createAccountWithBalance(donor); - await collection.addAdmin(donor, {Ethereum: caller}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const BASE_URI = 'base/' + const SUFFIX = 'suffix1' + const URI = 'uri1' - await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller}); + const collectionHelpers = helper.ethNativeContract.collectionHelpers(caller); + const creatorMethod = mode === 'rft' ? 'createRFTCollection' : 'createNFTCollection' - expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; + const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p') - await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller}); + const contract = helper.ethNativeContract.collectionById(collectionId, mode, caller); + await contract.methods.addCollectionAdmin(bruh).send(); // to check that admin will work too + const collection1 = await helper.nft.getCollectionObject(collectionId); + const data1 = await collection1.getData() + expect(data1?.raw.flags.erc721metadata).to.be.false; expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; - }); - itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const tokenPropertyPermissions = [{ - key: 'URI', - permission: { - mutable: true, - collectionAdmin: true, - tokenOwner: false, - }, - }]; - const collection = await helper.rft.mintCollection(donor, {name: 'col', description: 'descr', tokenPrefix: 'COL', tokenPropertyPermissions}); + await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI) + .send({from: bruh}); - await collection.addAdmin(donor, {Ethereum: caller}); + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const collection2 = await helper.nft.getCollectionObject(collectionId); + const data2 = await collection2.getData() + expect(data2?.raw.flags.erc721metadata).to.be.true; - await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('1')).send({from: caller}); + const TPPs = data2?.raw.tokenPropertyPermissions + expect(TPPs?.length).to.equal(2); - expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; + expect(TPPs.find((tpp: ITokenPropertyPermission) => { + return tpp.key === "URI" && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner + })).to.be.not.null - await contract.methods.setCollectionProperty('ERC721Metadata', Buffer.from('0')).send({from: caller}); + expect(TPPs.find((tpp: ITokenPropertyPermission) => { + return tpp.key === "URISuffix" && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner + })).to.be.not.null + + expect(data2?.raw.properties?.find((property: IProperty) => { + return property.key === "baseURI" && property.value === BASE_URI + })).to.be.not.null + + const token1Result = await contract.methods.mint(bruh).send(); + const tokenId1 = token1Result.events.Transfer.returnValues.tokenId; + + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI); + + await contract.methods.setProperty(tokenId1, "URISuffix", Buffer.from(SUFFIX)).send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); - expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; + await contract.methods.setProperty(tokenId1, "URI", Buffer.from(URI)).send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI); + + await contract.methods.deleteProperty(tokenId1, "URI").send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); + + const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send(); + const tokenId2 = token2Result.events.Transfer.returnValues.tokenId; + + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI); + + await contract.methods.deleteProperty(tokenId2, "URI").send(); + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI); + + await contract.methods.setProperty(tokenId2, "URISuffix", Buffer.from(SUFFIX)).send(); + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX); + } + + itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => { + await checkERC721Metadata(helper, 'nft'); + }); + + itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => { + await checkERC721Metadata(helper, 'rft'); }); }); --- a/tests/src/eth/collectionSponsoring.test.ts +++ b/tests/src/eth/collectionSponsoring.test.ts @@ -33,9 +33,8 @@ await collection.addToAllowList(alice, {Ethereum: minter}); - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.equal('1'); - const result = await contract.methods.mint(minter, nextTokenId).send(); + const result = await contract.methods.mint(minter).send(); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { @@ -44,7 +43,7 @@ args: { from: '0x0000000000000000000000000000000000000000', to: minter, - tokenId: nextTokenId, + tokenId: '1', }, }, ]); @@ -62,11 +61,11 @@ // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; // result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner}); // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true; - + // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId); // await submitTransactionAsync(sponsor, confirmTx); // expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; - + // const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner}); // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address); // }); @@ -83,28 +82,26 @@ expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true; - + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; - + await collectionEvm.methods.removeCollectionSponsor().send({from: owner}); - + const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner}); expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000'); }); itEth('Sponsoring collection from evm address via access list', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)}); - const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); + const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', ''); + const collection = helper.nft.getCollectionObject(collectionId); const sponsor = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); + const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); + await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); let collectionData = (await collection.getData())!; expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); @@ -133,23 +130,17 @@ const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); { - const nextTokenId = await collectionEvm.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await collectionEvm.methods.mintWithTokenURI( - user, - nextTokenId, - 'Test URI', - ).send({from: user}); + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { - address: collectionIdAddress, + address: collectionAddress, event: 'Transfer', args: { from: '0x0000000000000000000000000000000000000000', to: user, - tokenId: nextTokenId, + tokenId: '1', }, }, ]); @@ -173,10 +164,10 @@ // const collectionEvm = evmCollection(web3, owner, collectionIdAddress); // await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner}); - + // const confirmTx = await api.tx.unique.confirmSponsorship(collectionId); // await submitTransactionAsync(sponsor, confirmTx); - + // const user = createEthAccount(web3); // const nextTokenId = await collectionEvm.methods.nextTokenId().call(); // expect(nextTokenId).to.be.equal('1'); @@ -221,39 +212,32 @@ itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - let result = await collectionHelpers.methods.createERC721MetadataCompatibleNFTCollection('Sponsor collection', '1', '1', '').send({value: Number(2n * nominal)}); - const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', ''); const collection = helper.nft.getCollectionObject(collectionId); const sponsor = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); + const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - result = await collectionEvm.methods.setCollectionSponsor(sponsor).send(); + await collectionEvm.methods.setCollectionSponsor(sponsor).send(); let collectionData = (await collection.getData())!; expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); - const sponsorCollection = helper.ethNativeContract.collection(collectionIdAddress, 'nft', sponsor); + const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); await sponsorCollection.methods.confirmCollectionSponsorship().send(); collectionData = (await collection.getData())!; expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); const user = helper.eth.createAccount(); await collectionEvm.methods.addCollectionAdmin(user).send(); - + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); - const userCollectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', user); - const nextTokenId = await userCollectionEvm.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - result = await userCollectionEvm.methods.mintWithTokenURI( - user, - nextTokenId, - 'Test URI', - ).send(); + const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', user); + + let result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI',).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const events = helper.eth.normalizeEvents(result.events); const address = helper.ethAddress.fromCollectionId(collectionId); @@ -265,12 +249,12 @@ args: { from: '0x0000000000000000000000000000000000000000', to: user, - tokenId: nextTokenId, + tokenId: '1', }, }, ]); - expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - + expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); --- a/tests/src/eth/fractionalizer/Fractionalizer.sol +++ b/tests/src/eth/fractionalizer/Fractionalizer.sol @@ -124,8 +124,7 @@ address rftTokenAddress; UniqueRefungibleToken rftTokenContract; if (nft2rftMapping[_collection][_token] == 0) { - rftTokenId = rftCollectionContract.nextTokenId(); - rftCollectionContract.mint(address(this), rftTokenId); + rftTokenId = rftCollectionContract.mint(address(this)); rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId); nft2rftMapping[_collection][_token] = rftTokenId; rft2nftMapping[rftTokenAddress] = Token(_collection, _token); --- a/tests/src/eth/fractionalizer/fractionalizer.test.ts +++ b/tests/src/eth/fractionalizer/fractionalizer.test.ts @@ -64,8 +64,8 @@ }> => { const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner}); await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner}); @@ -148,8 +148,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; const {contract: fractionalizer} = await initContract(helper, owner); @@ -280,8 +280,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; const fractionalizer = await deployContract(helper, owner); @@ -295,8 +295,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; await nftContract.methods.transfer(nftOwner, 1).send({from: owner}); @@ -312,8 +312,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; const {contract: fractionalizer} = await initContract(helper, owner); @@ -327,8 +327,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; const {contract: fractionalizer} = await initContract(helper, owner); @@ -343,9 +343,9 @@ const fractionalizer = await deployContract(helper, owner); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); - const rftTokenId = await refungibleContract.methods.nextTokenId().call(); - await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner}); - + const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); + const rftTokenId = mintResult.events.Transfer.returnValues.tokenId; + await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call({from: owner})) .to.be.rejectedWith(/RFT collection is not set$/g); }); @@ -356,9 +356,9 @@ const {contract: fractionalizer} = await initContract(helper, owner); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); - const rftTokenId = await refungibleContract.methods.nextTokenId().call(); - await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner}); - + const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); + const rftTokenId = mintResult.events.Transfer.returnValues.tokenId; + await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call()) .to.be.rejectedWith(/Wrong RFT collection$/g); }); @@ -373,9 +373,9 @@ await refungibleContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner}); - const rftTokenId = await refungibleContract.methods.nextTokenId().call(); - await refungibleContract.methods.mint(owner, rftTokenId).send({from: owner}); - + const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); + const rftTokenId = mintResult.events.Transfer.returnValues.tokenId; + await expect(fractionalizer.methods.rft2nft(rftCollection.collectionAddress, rftTokenId).call()) .to.be.rejectedWith(/No corresponding NFT token found$/g); }); @@ -386,7 +386,7 @@ const {contract: fractionalizer, rftCollectionAddress} = await initContract(helper, owner); const {rftTokenAddress} = await mintRFTToken(helper, owner, fractionalizer, 100n); - + const {tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress); const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner); await refungibleTokenContract.methods.transfer(receiver, 50).send({from: owner}); @@ -420,7 +420,7 @@ await expect(fractionalizer.methods.nft2rft(nftCollectionAddress, nftToken.tokenId, 100).call()) .to.be.rejectedWith(/TransferNotAllowed$/g); }); - + itEth('fractionalize NFT with RFT transfers disallowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); @@ -434,8 +434,8 @@ const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); - const nftTokenId = await nftContract.methods.nextTokenId().call(); - await nftContract.methods.mint(owner, nftTokenId).send({from: owner}); + const mintResult = await nftContract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; await fractionalizer.methods.setNftCollectionIsAllowed(nftCollection.collectionAddress, true).send({from: owner}); await nftContract.methods.approve(fractionalizer.options.address, nftTokenId).send({from: owner}); --- a/tests/src/eth/nesting/nest.test.ts +++ b/tests/src/eth/nesting/nest.test.ts @@ -29,74 +29,53 @@ itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionId, contract} = await createNestingCollection(helper, owner); - - // Create a token to be nested - const targetNFTTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetNFTTokenId, - ).send({from: owner}); - + + // Create a token to be nested to + const mintingTargetNFTTokenIdResult = await contract.methods.mint(owner).send({from: owner}); + const targetNFTTokenId = mintingTargetNFTTokenIdResult.events.Transfer.returnValues.tokenId; const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId); - + // Create a nested token - const firstTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - targetNftTokenAddress, - firstTokenId, - ).send({from: owner}); - + const mintingFirstTokenIdResult = await contract.methods.mint(targetNftTokenAddress).send({from: owner}); + const firstTokenId = mintingFirstTokenIdResult.events.Transfer.returnValues.tokenId; expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress); - + // Create a token to be nested and nest - const secondTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - secondTokenId, - ).send({from: owner}); - + const mintingSecondTokenIdResult = await contract.methods.mint(owner).send({from: owner}); + const secondTokenId = mintingSecondTokenIdResult.events.Transfer.returnValues.tokenId; + await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner}); - expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress); - + // Unnest token back await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner}); expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner); }); - + itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner); await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); - + // Create a token to nest into - const targetNftTokenId = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - targetNftTokenId, - ).send({from: owner}); + const mintingtargetNftTokenIdResult = await contractA.methods.mint(owner).send({from: owner}); + const targetNftTokenId = mintingtargetNftTokenIdResult.events.Transfer.returnValues.tokenId; const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId); - + // Create a token for nesting in the same collection as the target - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); - + const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner}); + const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId; + // Create a token for nesting in a different collection - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - owner, - nftTokenIdB, - ).send({from: owner}); - + const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner}); + const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId; + // Nest await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner}); expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1); - + await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner}); expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1); }); @@ -105,112 +84,88 @@ describe('Negative Test: EVM Nesting', async() => { itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - + const {collectionId, contract} = await createNestingCollection(helper, owner); await contract.methods.setCollectionNesting(false).send({from: owner}); - + // Create a token to nest into - const targetNftTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetNftTokenId, - ).send({from: owner}); - - const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNftTokenId); - + const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner}); + const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId; + const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId); + // Create a token to nest - const nftTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - nftTokenId, - ).send({from: owner}); - + const mintingNftTokenIdResult = await contract.methods.mint(owner).send({from: owner}); + const nftTokenId = mintingNftTokenIdResult.events.Transfer.returnValues.tokenId; + // Try to nest await expect(contract.methods .transfer(targetNftTokenAddress, nftTokenId) .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const malignant = await helper.eth.createAccountWithBalance(donor); - + const {collectionId, contract} = await createNestingCollection(helper, owner); - + // Mint a token - const targetTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - owner, - targetTokenId, - ).send({from: owner}); + const mintingTargetTokenIdResult = await contract.methods.mint(owner).send({from: owner}); + const targetTokenId = mintingTargetTokenIdResult.events.Transfer.returnValues.tokenId; const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId); - + // Mint a token belonging to a different account - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint( - malignant, - tokenId, - ).send({from: owner}); - + const mintingTokenIdResult = await contract.methods.mint(malignant).send({from: owner}); + const tokenId = mintingTokenIdResult.events.Transfer.returnValues.tokenId; + // Try to nest one token in another as a non-owner account await expect(contract.methods .transfer(targetTokenAddress, tokenId) .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const malignant = await helper.eth.createAccountWithBalance(donor); - + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner); - + await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner}); - + // Create a token in one collection - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); + const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner}); + const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId; const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA); - - // Create a token in another collection belonging to someone else - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - malignant, - nftTokenIdB, - ).send({from: owner}); - + + // Create a token in another collection + const mintingTokenIdBResult = await contractB.methods.mint(malignant).send({from: owner}); + const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId; + // Try to drag someone else's token into the other collection and nest await expect(contractB.methods .transfer(nftTokenAddressA, nftTokenIdB) .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - + const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner); const {contract: contractB} = await createNestingCollection(helper, owner); - + await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner}); - + // Create a token in one collection - const nftTokenIdA = await contractA.methods.nextTokenId().call(); - await contractA.methods.mint( - owner, - nftTokenIdA, - ).send({from: owner}); + const mintingTokenIdAResult = await contractA.methods.mint(owner).send({from: owner}); + const nftTokenIdA = mintingTokenIdAResult.events.Transfer.returnValues.tokenId; const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA); - + // Create a token in another collection - const nftTokenIdB = await contractB.methods.nextTokenId().call(); - await contractB.methods.mint( - owner, - nftTokenIdB, - ).send({from: owner}); - + const mintingTokenIdBResult = await contractB.methods.mint(owner).send({from: owner}); + const nftTokenIdB = mintingTokenIdBResult.events.Transfer.returnValues.tokenId; + + // Try to nest into a token in the other collection, disallowed in the first await expect(contractB.methods .transfer(nftTokenAddressA, nftTokenIdB) --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -29,7 +29,7 @@ [alice] = await helper.arrange.createAccounts([10n], donor); }); }); - + itEth('totalSupply', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); await collection.mintToken(alice); @@ -95,26 +95,23 @@ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', baseUri); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mint( - receiver, - nextTokenId, - ).send(); + const result = await contract.methods.mint(receiver).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); + if (propertyKey && propertyValue) { // Set URL or suffix - await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send(); + await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send(); } const event = result.events.Transfer; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); expect(event.returnValues.to).to.be.equal(receiver); - expect(event.returnValues.tokenId).to.be.equal(nextTokenId); + expect(event.returnValues.tokenId).to.be.equal(tokenId); - return {contract, nextTokenId}; + return {contract, nextTokenId: tokenId}; } itEth('Empty tokenURI', async ({helper}) => { @@ -156,22 +153,17 @@ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', '6', '6', ''); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).send(); + const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send(); + const tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); const event = result.events.Transfer; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); expect(event.returnValues.to).to.be.equal(receiver); - expect(event.returnValues.tokenId).to.be.equal(nextTokenId); - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); // TODO: this wont work right now, need release 919000 first // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send(); @@ -224,7 +216,7 @@ { const result = await contract.methods.burn(tokenId).send({from: caller}); - + const event = result.events.Transfer; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal(caller); @@ -330,7 +322,7 @@ [alice] = await helper.arrange.createAccounts([10n], donor); }); }); - + itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const spender = helper.eth.createAccount(); @@ -409,7 +401,7 @@ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); - + const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); @@ -433,7 +425,7 @@ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); - + const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); @@ -459,14 +451,14 @@ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); - + const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); }); await token.transferFrom(bob, {Substrate: alice.address}, {Ethereum: receiver}); - + const event = events[0]; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address)); @@ -482,14 +474,14 @@ const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); - + const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); }); await token.transfer(alice, {Ethereum: receiver}); - + const event = events[0]; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal(helper.address.substrateToEth(alice.address)); @@ -558,4 +550,4 @@ const symbol = await contract.methods.symbol().call(); expect(symbol).to.equal('CHANGE'); }); -}); \ No newline at end of file +}); --- a/tests/src/eth/payable.test.ts +++ b/tests/src/eth/payable.test.ts @@ -118,7 +118,7 @@ const deployer = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); const contract = await helper.eth.deployFlipper(deployer); - + const initialCallerBalance = await helper.balance.getEthereum(caller); await contract.methods.flip().send({from: caller}); const finalCallerBalance = await helper.balance.getEthereum(caller); @@ -129,7 +129,7 @@ const deployer = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); const contract = await deployProxyContract(helper, deployer); - + const initialCallerBalance = await helper.balance.getEthereum(caller); const initialContractBalance = await helper.balance.getEthereum(contract.options.address); await contract.methods.flip().send({from: caller}); @@ -138,7 +138,7 @@ expect(finalCallerBalance < initialCallerBalance).to.be.true; expect(finalContractBalance == initialContractBalance).to.be.true; }); - + itEth('Fee for nested calls to native methods is withdrawn from the user', async({helper}) => { const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal(); @@ -155,7 +155,7 @@ expect(finalCallerBalance < initialCallerBalance).to.be.true; expect(finalContractBalance == initialContractBalance).to.be.true; }); - + itEth('Fee for nested calls to create*Collection methods is withdrawn from the user and from the contract', async({helper}) => { const CONTRACT_BALANCE = 2n * helper.balance.getOneTokenNominal(); const deployer = await helper.eth.createAccountWithBalance(donor); @@ -176,7 +176,7 @@ const BIG_FEE = 3n * helper.balance.getOneTokenNominal(); const caller = await helper.eth.createAccountWithBalance(donor); const collectionHelper = helper.ethNativeContract.collectionHelpers(caller); - + await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); @@ -186,7 +186,7 @@ const BIG_FEE = 3n * helper.balance.getOneTokenNominal(); const caller = await helper.eth.createAccountWithBalance(donor); const collectionHelper = helper.ethNativeContract.collectionHelpers(caller); - + await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); @@ -235,8 +235,7 @@ function mintNftToken(address collectionAddress) external { UniqueNFT collection = UniqueNFT(collectionAddress); - uint256 tokenId = collection.nextTokenId(); - collection.mint(msg.sender, tokenId); + uint256 tokenId = collection.mint(msg.sender); emit TokenMinted(tokenId); } --- a/tests/src/eth/proxy/UniqueNFTProxy.sol +++ b/tests/src/eth/proxy/UniqueNFTProxy.sol @@ -120,20 +120,19 @@ return proxied.mintingFinished(); } - function mint(address to, uint256 tokenId) + function mint(address to) external override - returns (bool) + returns (uint256) { - return proxied.mint(to, tokenId); + return proxied.mint(to); } function mintWithTokenURI( address to, - uint256 tokenId, string memory tokenUri - ) external override returns (bool) { - return proxied.mintWithTokenURI(to, tokenId, tokenUri); + ) external override returns (uint256) { + return proxied.mintWithTokenURI(to, tokenUri); } function finishMinting() external override returns (bool) { @@ -169,7 +168,7 @@ return proxied.mintBulk(to, tokenIds); } - function mintBulkWithTokenURI(address to, Tuple0[] memory tokens) + function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) external override returns (bool) --- a/tests/src/eth/proxy/nonFungibleProxy.test.ts +++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts @@ -111,13 +111,10 @@ await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send(); { - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).send({from: caller}); + const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send({from: caller}); + const tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); + const events = helper.eth.normalizeEvents(result.events); events[0].address = events[0].address.toLocaleLowerCase(); @@ -128,12 +125,12 @@ args: { from: '0x0000000000000000000000000000000000000000', to: receiver, - tokenId: nextTokenId, + tokenId, }, }, ]); - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); } }); --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -33,8 +33,9 @@ const caller = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'TotalSupply', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const nextTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, nextTokenId).send(); + + await contract.methods.mint(caller).send(); + const totalSupply = await contract.methods.totalSupply().call(); expect(totalSupply).to.equal('1'); }); @@ -44,18 +45,9 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'BalanceOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - { - const nextTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, nextTokenId).send(); - } - { - const nextTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, nextTokenId).send(); - } - { - const nextTokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, nextTokenId).send(); - } + await contract.methods.mint(caller).send(); + await contract.methods.mint(caller).send(); + await contract.methods.mint(caller).send(); const balance = await contract.methods.balanceOf(caller).call(); expect(balance).to.equal('3'); @@ -66,8 +58,8 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const owner = await contract.methods.ownerOf(tokenId).call(); expect(owner).to.equal(caller); @@ -79,8 +71,8 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf-AfterBurn', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); @@ -98,8 +90,8 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); @@ -126,22 +118,17 @@ const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', ''); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); - - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mintWithTokenURI( - receiver, - nextTokenId, - 'Test URI', - ).send(); + const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send(); + const event = result.events.Transfer; expect(event.address).to.equal(collectionAddress); expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000'); expect(event.returnValues.to).to.equal(receiver); - expect(event.returnValues.tokenId).to.equal(nextTokenId); + const tokenId = event.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); - expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); }); itEth('Can perform mintBulk()', async ({helper}) => { @@ -182,8 +169,8 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; { const result = await contract.methods.burn(tokenId).send(); const event = result.events.Transfer; @@ -200,9 +187,10 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; + const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); - await contract.methods.mint(caller, tokenId).send(); const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller); await tokenContract.methods.repartition(15).send(); @@ -244,12 +232,12 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; { const result = await contract.methods.transfer(receiver, tokenId).send(); - + const event = result.events.Transfer; expect(event.address).to.equal(collectionAddress); expect(event.returnValues.from).to.equal(caller); @@ -274,8 +262,8 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); @@ -301,8 +289,8 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); @@ -339,8 +327,8 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transferFrom(caller, receiver, tokenId).send()); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -353,8 +341,8 @@ const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const cost = await helper.eth.recordCallFee(caller, () => contract.methods.transfer(receiver, tokenId).send()); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -394,7 +382,7 @@ tokenPropertyPermissions, }, ); - + const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller); const name = await contract.methods.name().call(); expect(name).to.equal('Leviathan'); --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -82,26 +82,22 @@ const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); - - const nextTokenId = await contract.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - const result = await contract.methods.mint( - receiver, - nextTokenId, - ).send(); - if (propertyKey && propertyValue) { - // Set URL or suffix - await contract.methods.setProperty(nextTokenId, propertyKey, Buffer.from(propertyValue)).send(); - } + const result = await contract.methods.mint(receiver).send(); const event = result.events.Transfer; + const tokenId = event.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); expect(event.returnValues.to).to.be.equal(receiver); - expect(event.returnValues.tokenId).to.be.equal(nextTokenId); - return {contract, nextTokenId}; + if (propertyKey && propertyValue) { + // Set URL or suffix + await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send(); + } + + return {contract, nextTokenId: tokenId}; } itEth('Empty tokenURI', async ({helper}) => { @@ -295,8 +291,8 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6'); const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); - const tokenId = await contract.methods.nextTokenId().call(); - await contract.methods.mint(caller, tokenId).send(); + const result = await contract.methods.mint(caller).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller); @@ -479,9 +475,10 @@ const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN'); const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); - - const tokenId = await collectionContract.methods.nextTokenId().call(); - await collectionContract.methods.mint(owner, tokenId).send(); + + const result = await collectionContract.methods.mint(owner).send(); + const tokenId = result.events.Transfer.returnValues.tokenId; + const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner); --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -43,12 +43,12 @@ if(!imports) return function(path: string) { return {error: `File not found: ${path}`}; }; - + const knownImports = {} as {[key: string]: string}; for(const imp of imports) { knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString(); } - + return function(path: string) { if(path in knownImports) return {contents: knownImports[path]}; return {error: `File not found: ${path}`}; @@ -71,7 +71,7 @@ }, }, }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name]; - + return { abi: out.abi, object: '0x' + out.evm.bytecode.object, @@ -94,7 +94,7 @@ } } - + class NativeContractGroup extends EthGroupBase { contractHelpers(caller: string): Contract { @@ -145,14 +145,14 @@ async createAccountWithBalance(donor: IKeyringPair, amount=1000n) { const account = this.createAccount(); await this.transferBalanceFromSubstrate(donor, account, amount); - + return account; } async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount=1000n, inTokens=true) { return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n)); } - + async getCollectionCreationFee(signer: string) { const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); return await collectionHelper.methods.collectionCreationFee().call(); @@ -177,7 +177,7 @@ async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - + const result = await collectionHelper.methods.createNFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); @@ -187,13 +187,11 @@ } async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> { - const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - - const result = await collectionHelper.methods.createERC721MetadataCompatibleNFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)}); - const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + const {collectionId, collectionAddress} = await this.createNFTCollection(signer, name, description, tokenPrefix) + + await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send(); return {collectionId, collectionAddress}; } @@ -201,7 +199,7 @@ async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - + const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); @@ -211,13 +209,11 @@ } async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> { - const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - - const result = await collectionHelper.methods.createERC721MetadataCompatibleRFTCollection(name, description, tokenPrefix, baseUri).send({value: Number(collectionCreationPrice)}); - const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + const {collectionId, collectionAddress} = await this.createRFTCollection(signer, name, description, tokenPrefix) + + await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send(); return {collectionId, collectionAddress}; } @@ -312,7 +308,7 @@ }; return await this.helper.arrange.calculcateFee(address, wrappedCode); } -} +} class EthAddressGroup extends EthGroupBase { extractCollectionId(address: string): number { @@ -343,8 +339,8 @@ normalizeAddress(address: string): string { return '0x' + address.substring(address.length - 40); } -} - +} + export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper; export class EthUniqueHelper extends DevUniqueHelper { @@ -396,4 +392,3 @@ return newHelper; } } - \ No newline at end of file