difftreelog
Merge pull request #788 from UniqueNetwork/tests/eth-helpers
in: master
60 files changed
tests/src/.outdated/rmrk/acceptNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/addResource.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/addTheme.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/burnNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/createBase.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/createCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/deleteCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/equipNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/getOwnedNfts.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/lockCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/mintNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/rejectNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/removeResource.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/rmrkIsolation.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/sendNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/setCollectionProperty.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/setEquippableList.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/setNftProperty.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/setResourcePriorities.seqtest.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/util/fetch.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/util/helpers.tsdiffbeforeafterbothno changes
tests/src/.outdated/rmrk/util/tx.tsdiffbeforeafterbothno changes
tests/src/.outdated/substrate/get-balance.tsdiffbeforeafterbothno changes
tests/src/.outdated/substrate/privateKey.tsdiffbeforeafterbothno changes
tests/src/.outdated/substrate/promisify-substrate.tsdiffbeforeafterbothno changes
tests/src/.outdated/substrate/substrate-api.tsdiffbeforeafterbothno changes
tests/src/.outdated/substrate/wait-new-blocks.tsdiffbeforeafterbothno changes
tests/src/calibrateApply.tsdiffbeforeafterboth1import {readFile, writeFile} from 'fs/promises';1import {readFile, writeFile} from 'fs/promises';2import path from 'path';2import path from 'path';3import usingApi from './substrate/substrate-api';3import usingApi from './.outdated/substrate/substrate-api';445const formatNumber = (num: string): string => num.split('').reverse().join('').replace(/([0-9]{3})/g, '$1_').split('').reverse().join('').replace(/^_/, '');5const formatNumber = (num: string): string => num.split('').reverse().join('').replace(/([0-9]{3})/g, '$1_').split('').reverse().join('').replace(/^_/, '');66tests/src/eth/allowlist.test.tsdiffbeforeafterboth15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {Pallets} from '../util';18import {itEth, usingEthPlaygrounds, expect} from './util';19import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util';192020describe('EVM contract allowlist', () => {21describe('EVM contract allowlist', () => {21 let donor: IKeyringPair;22 let donor: IKeyringPair;92 });93 });93949596 [97 {mode: 'nft' as const, requiredPallets: []},98 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},99 {mode: 'ft' as const, requiredPallets: []},100 ].map(testCase => 94 itEth('Collection allowlist can be added and removed by [cross] address', async ({helper}) => {101 itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {95 const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();102 const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();96 const [userSub] = await helper.arrange.createAccounts([10n], donor);103 const [userSub] = await helper.arrange.createAccounts([10n], donor);97 const userEth = await helper.eth.createAccountWithBalance(donor);104 const userEth = await helper.eth.createAccountWithBalance(donor);98 105 const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth];106 99 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');107 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');100 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);108 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);101 const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);109 const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);102 const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);110 const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);103 const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);111 const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);108 await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});116 await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});109 await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});117 await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});118119 // Accounts are in allowed list:110 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;120 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;111 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;121 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;112 expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;122 expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;113 expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;123 expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;114124 115 await collectionEvm.methods.mint(userEth).send(); // token #1125 await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1116 await collectionEvm.methods.mint(userEth).send(); // token #2126 await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2117 await collectionEvm.methods.setCollectionAccess(1).send();127 await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner});118 128 119 // allowlisted account can transfer and transferCross:129 // allowlisted account can transfer and transferCross from eth:120 await collectionEvm.methods.transfer(owner, 1).send({from: userEth});130 await collectionEvm.methods.transfer(owner, 1).send({from: userEth});121 await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});131 await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});132133 if (testCase.mode === 'ft') {134 expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n);135 expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n);136 } else {122 expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});137 expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});123 expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});138 expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});124 139 }140141 // allowlisted cross substrate accounts can transfer from Substrate:142 testCase.mode === 'ft'143 ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n)144 : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth});145 125 // can removeFromCollectionAllowListCross:146 // can removeFromCollectionAllowListCross:126 await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});147 await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});131 expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;152 expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;132153 133 // cannot transfer anymore154 // cannot transfer anymore134 await collectionEvm.methods.mint(userEth).send();155 await collectionEvm.methods.mint(...mintParams).send({from: owner});135 await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);156 await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);136 });157 }));137158159 [160 // cross-methods161 {mode: 'nft' as const, cross: true, requiredPallets: []},162 {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]},163 {mode: 'ft' as const, cross: true, requiredPallets: []},138 // Soft-deprecated164 // soft-deprecated165 {mode: 'nft' as const, cross: false, requiredPallets: []},166 {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]},167 {mode: 'ft' as const, cross: false, requiredPallets: []},168 ].map(testCase => 139 itEth('Collection allowlist can not be add and remove [eth] address by not owner', async ({helper}) => {169 itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {170 // Select methods:171 const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList';172 const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList';173140 const owner = await helper.eth.createAccountWithBalance(donor);174 const owner = await helper.eth.createAccountWithBalance(donor);141 const notOwner = await helper.eth.createAccountWithBalance(donor);175 const notOwner = await helper.eth.createAccountWithBalance(donor);176 const userSub = donor;177 const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);142 const user = helper.eth.createAccount();178 const userEth = helper.eth.createAccount();143 const crossUser = helper.ethCrossAccount.fromAddress(user);179 const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);144180145 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');181 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');146 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);182 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);147183 148 expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;184 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;185 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;186 187 // 1. notOwner cannot add to allow list:188 // 1.1 plain ethereum or cross address:149 await expect(collectionEvm.methods.addToCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission');189 await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');190 // 1.2 cross-substrate address:191 if (testCase.cross)150 expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;192 await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');193194 // 2. owner can add to allow list:195 // 2.1 plain ethereum or cross address:151 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});196 await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner});197 // 2.2 cross-substrate address:198 if (testCase.cross) {152 expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;199 await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner});200 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;201 }202 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;203 204 // 3. notOwner cannot remove from allow list:205 // 3.1 plain ethereum or cross address:153 await expect(collectionEvm.methods.removeFromCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission');206 await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');207 // 3.2 cross-substrate address:208 if (testCase.cross)154 expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;209 await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');155 });210 }));156157 itEth('Collection allowlist can not be add and remove [cross] address by not owner', async ({helper}) => {158 const owner = await helper.eth.createAccountWithBalance(donor);159 const notOwner = await helper.eth.createAccountWithBalance(donor);160 const user = donor;161 162 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');163 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);164 165 expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;166 const userCross = helper.ethCrossAccount.fromKeyringPair(user);167 await expect(collectionEvm.methods.addToCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');168 expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;169 await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});170 171 expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;172 await expect(collectionEvm.methods.removeFromCollectionAllowListCross(userCross).call({from: notOwner})).to.be.rejectedWith('NoPermission');173 expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;174 });175});211});176212tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth208 }208 }209 });209 });210 210 211 itEth('Can perform transferFrom()', async ({helper}) => {211 [212 'transferFrom',213 'transferFromCross',214 ].map(testCase => 215 itEth(`Can perform ${testCase}`, async ({helper}) => {212 const owner = await helper.eth.createAccountWithBalance(donor);216 const isCross = testCase === 'transferFromCross';217 const owner = await helper.eth.createAccountWithBalance(donor);213 const spender = await helper.eth.createAccountWithBalance(donor);218 const ownerCross = helper.ethCrossAccount.fromAddress(owner);219 const spender = await helper.eth.createAccountWithBalance(donor);214 const receiver = helper.eth.createAccount();220 const receiverEth = helper.eth.createAccount();215 const collection = await helper.rft.mintCollection(alice);221 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);222 const [receiverSub] = await helper.arrange.createAccounts([1n], donor);223 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);224 225 const collection = await helper.rft.mintCollection(alice);216 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});226 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});217227218 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);228 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);219 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);229 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);220230221 await contract.methods.approve(spender, 100).send();231 await contract.methods.approve(spender, 100).send({from: owner});232 233 // 1. Can transfer from234 // 1.1 Plain ethereum or cross address:235 {236 const result = await contract.methods[testCase](237 isCross ? ownerCross : owner,238 isCross ? receiverCrossEth : receiverEth, 239 49,240 ).send({from: spender});222241223 {242 // Check events:224 const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});225 let event = result.events.Transfer;243 const transferEvent = result.events.Transfer;226 expect(event.address).to.be.equal(tokenAddress);244 expect(transferEvent.address).to.be.equal(tokenAddress);227 expect(event.returnValues.from).to.be.equal(owner);245 expect(transferEvent.returnValues.from).to.be.equal(owner);228 expect(event.returnValues.to).to.be.equal(receiver);246 expect(transferEvent.returnValues.to).to.be.equal(receiverEth);229 expect(event.returnValues.value).to.be.equal('49');247 expect(transferEvent.returnValues.value).to.be.equal('49');230248231 event = result.events.Approval;249 const approvalEvent = result.events.Approval;232 expect(event.address).to.be.equal(tokenAddress);250 expect(approvalEvent.address).to.be.equal(tokenAddress);233 expect(event.returnValues.owner).to.be.equal(owner);251 expect(approvalEvent.returnValues.owner).to.be.equal(owner);234 expect(event.returnValues.spender).to.be.equal(spender);252 expect(approvalEvent.returnValues.spender).to.be.equal(spender);235 expect(event.returnValues.value).to.be.equal('51');253 expect(approvalEvent.returnValues.value).to.be.equal('51');236 }237254238 {255 // Check balances:239 const balance = await contract.methods.balanceOf(receiver).call();256 const receiverBalance = await contract.methods.balanceOf(receiverEth).call();240 expect(+balance).to.equal(49);257 const ownerBalance = await contract.methods.balanceOf(owner).call();241 }242258243 {259 expect(+receiverBalance).to.equal(49);244 const balance = await contract.methods.balanceOf(owner).call();245 expect(+balance).to.equal(151);246 }260 expect(+ownerBalance).to.equal(151);247 });248 249 itEth('Can perform transferFromCross()', async ({helper}) => {250 const owner = await helper.eth.createAccountWithBalance(donor);251 const ownerCross = helper.ethCrossAccount.fromAddress(owner);261 }252 const spender = await helper.eth.createAccountWithBalance(donor);253 const receiver = helper.eth.createAccount();254 const receiverSub = (await helper.arrange.createAccounts([1n], donor))[0];255 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiver);256 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);257 262 258 const collection = await helper.rft.mintCollection(alice);263 // 1.2 Cross substrate address:264 if (testCase === 'transferFromCross') {265 const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender});259 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});266 // Check events:267 const transferEvent = result.events.Transfer;268 expect(transferEvent.address).to.be.equal(tokenAddress);269 expect(transferEvent.returnValues.from).to.be.equal(owner);270 expect(transferEvent.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));271 expect(transferEvent.returnValues.value).to.be.equal('51');260272261 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);273 const approvalEvent = result.events.Approval;274 expect(approvalEvent.address).to.be.equal(tokenAddress);275 expect(approvalEvent.returnValues.owner).to.be.equal(owner);262 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);276 expect(approvalEvent.returnValues.spender).to.be.equal(spender);277 expect(approvalEvent.returnValues.value).to.be.equal('0');263278264 await contract.methods.approve(spender, 100).send({from: owner});279 // Check balances:265 266 {280 const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});267 const result = await contract.methods.transferFromCross(ownerCross, receiverCrossEth, 49).send({from: spender});268 let event = result.events.Transfer;281 const ownerBalance = await contract.methods.balanceOf(owner).call();269 expect(event.address).to.be.equal(tokenAddress);270 expect(event.returnValues.from).to.be.equal(owner);282 expect(receiverBalance).to.equal(51n);271 expect(event.returnValues.to).to.be.equal(receiver);283 expect(+ownerBalance).to.equal(100);272 expect(event.returnValues.value).to.be.equal('49');284 }285 }));273286274 event = result.events.Approval;287 [288 'transfer',289 'transferCross',290 ].map(testCase => 275 expect(event.address).to.be.equal(tokenAddress);291 itEth(`Can perform ${testCase}()`, async ({helper}) => {292 const isCross = testCase === 'transferCross';276 expect(event.returnValues.owner).to.be.equal(owner);293 const owner = await helper.eth.createAccountWithBalance(donor);294 const receiverEth = helper.eth.createAccount();277 expect(event.returnValues.spender).to.be.equal(spender);295 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);296 const [receiverSub] = await helper.arrange.createAccounts([1n], donor);278 expect(event.returnValues.value).to.be.equal('51');297 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);298 const collection = await helper.rft.mintCollection(alice);279 }299 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});280300281 {301 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);282 const balance = await contract.methods.balanceOf(receiver).call();283 expect(+balance).to.equal(49);302 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);284 }285303286 {304 // 1. Can transfer to plain ethereum or cross-ethereum account:305 {287 const balance = await contract.methods.balanceOf(owner).call();306 const result = await contract.methods[testCase](isCross ? receiverCrossEth : receiverEth, 50).send({from: owner});307 // Check events308 const transferEvent = result.events.Transfer;309 expect(transferEvent.address).to.be.equal(tokenAddress);310 expect(transferEvent.returnValues.from).to.be.equal(owner);311 expect(transferEvent.returnValues.to).to.be.equal(receiverEth);312 expect(transferEvent.returnValues.value).to.be.equal('50');313 // Check balances:314 const ownerBalance = await contract.methods.balanceOf(owner).call();288 expect(+balance).to.equal(151);315 const receiverBalance = await contract.methods.balanceOf(receiverEth).call();316 expect(+ownerBalance).to.equal(150);317 expect(+receiverBalance).to.equal(50);289 }318 }290 319 291 {320 // 2. Can transfer to cross-substrate account: 321 if(isCross) {292 const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender});322 const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner});293 let event = result.events.Transfer;323 // Check events:324 const event = result.events.Transfer;294 expect(event.address).to.be.equal(tokenAddress);325 expect(event.address).to.be.equal(tokenAddress);295 expect(event.returnValues.from).to.be.equal(owner);326 expect(event.returnValues.from).to.be.equal(owner);296 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));327 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));297 expect(event.returnValues.value).to.be.equal('51');328 expect(event.returnValues.value).to.be.equal('50');329 // Check balances:330 const ownerBalance = await contract.methods.balanceOf(owner).call();331 const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});332 expect(+ownerBalance).to.equal(100);333 expect(receiverBalance).to.equal(50n);334 }335 }));298336299 event = result.events.Approval;300 expect(event.address).to.be.equal(tokenAddress);301 expect(event.returnValues.owner).to.be.equal(owner);302 expect(event.returnValues.spender).to.be.equal(spender);303 expect(event.returnValues.value).to.be.equal('0');304 }305306 {307 const balance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});308 expect(balance).to.equal(51n);309 }310311 {312 const balance = await contract.methods.balanceOf(owner).call();313 expect(+balance).to.equal(100);314 }315 });316317 itEth('Can perform transfer()', async ({helper}) => {318 const owner = await helper.eth.createAccountWithBalance(donor);319 const receiver = helper.eth.createAccount();320 const collection = await helper.rft.mintCollection(alice);321 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});322323 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);324 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);325326 {327 const result = await contract.methods.transfer(receiver, 50).send({from: owner});328 const event = result.events.Transfer;329 expect(event.address).to.be.equal(tokenAddress);330 expect(event.returnValues.from).to.be.equal(owner);331 expect(event.returnValues.to).to.be.equal(receiver);332 expect(event.returnValues.value).to.be.equal('50');333 }334335 {336 const balance = await contract.methods.balanceOf(owner).call();337 expect(+balance).to.equal(150);338 }339340 {341 const balance = await contract.methods.balanceOf(receiver).call();342 expect(+balance).to.equal(50);343 }344 });345 346 [337 [347 'transfer',338 'transfer',348 // 'transferCross', // TODO339 'transferCross',349 ].map(testCase => 340 ].map(testCase => 350 itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => {341 itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => {342 const isCross = testCase === 'transferCross';351 const owner = await helper.eth.createAccountWithBalance(donor);343 const owner = await helper.eth.createAccountWithBalance(donor);352 const receiver = await helper.eth.createAccountWithBalance(donor);344 const ownerCross = helper.ethCrossAccount.fromAddress(owner);345 const receiverEth = await helper.eth.createAccountWithBalance(donor);346 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);353 const collection = await helper.rft.mintCollection(alice);347 const collection = await helper.rft.mintCollection(alice);354 const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner});348 const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner});355 const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiver});349 const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiverEth});356 const tokenIdNonExist = 9999999;350 const tokenIdNonExist = 9999999;357 351 358 const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId);352 const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId);363 const tokenEvmNonExist = helper.ethNativeContract.rftToken(tokenAddressNonExist, owner);357 const tokenEvmNonExist = helper.ethNativeContract.rftToken(tokenAddressNonExist, owner);364 358 365 // 1. Can transfer zero amount (EIP-20):359 // 1. Can transfer zero amount (EIP-20):366 await tokenEvmOwner.methods[testCase](receiver, 0).send({from: owner});360 await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 0).send({from: owner});367 // 2. Cannot transfer non-owned token:361 // 2. Cannot transfer non-owned token:368 await expect(tokenEvmReceiver.methods[testCase](owner, 0).send({from: owner})).to.be.rejected;362 await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;369 await expect(tokenEvmReceiver.methods[testCase](owner, 5).send({from: owner})).to.be.rejected;363 await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;370 // 3. Cannot transfer non-existing token:364 // 3. Cannot transfer non-existing token:371 await expect(tokenEvmNonExist.methods[testCase](owner, 0).send({from: owner})).to.be.rejected;365 await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected;372 await expect(tokenEvmNonExist.methods[testCase](owner, 5).send({from: owner})).to.be.rejected;366 await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected;373367374 // 4. Storage is not corrupted:368 // 4. Storage is not corrupted:375 expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);369 expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);376 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]);370 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);377 expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]); // TODO371 expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]);378372379 // 4.1 Tokens can be transferred:373 // 4.1 Tokens can be transferred:380 await tokenEvmOwner.methods[testCase](receiver, 10).send({from: owner});374 await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 10).send({from: owner});381 await tokenEvmReceiver.methods[testCase](owner, 10).send({from: receiver});375 await tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 10).send({from: receiverEth});382 expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]);376 expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]);383 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);377 expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);384 }));378 }));385379386 itEth('Can perform transferCross()', async ({helper}) => {387 const owner = await helper.eth.createAccountWithBalance(donor);388 const receiver = helper.eth.createAccount();389 const receiverSub = (await helper.arrange.createAccounts([1n], donor))[0];390 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiver);391 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);392 const collection = await helper.rft.mintCollection(alice);393 const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner});394395 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId);396 const contract = helper.ethNativeContract.rftToken(tokenAddress, owner);397398 {399 const result = await contract.methods.transferCross(receiverCrossEth, 50).send({from: owner});400 const event = result.events.Transfer;401 expect(event.address).to.be.equal(tokenAddress);402 expect(event.returnValues.from).to.be.equal(owner);403 expect(event.returnValues.to).to.be.equal(receiver);404 expect(event.returnValues.value).to.be.equal('50');405 }406407 {408 const balance = await contract.methods.balanceOf(owner).call();409 expect(+balance).to.equal(150);410 }411412 {413 const balance = await contract.methods.balanceOf(receiver).call();414 expect(+balance).to.equal(50);415 }416 417 {418 const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner});419 const event = result.events.Transfer;420 expect(event.address).to.be.equal(tokenAddress);421 expect(event.returnValues.from).to.be.equal(owner);422 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address));423 expect(event.returnValues.value).to.be.equal('50');424 }425426 {427 const balance = await contract.methods.balanceOf(owner).call();428 expect(+balance).to.equal(100);429 }430431 {432 const balance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address});433 expect(balance).to.equal(50n);434 }435 });436 itEth('Can perform repartition()', async ({helper}) => {380 itEth('Can perform repartition()', async ({helper}) => {437 const owner = await helper.eth.createAccountWithBalance(donor);381 const owner = await helper.eth.createAccountWithBalance(donor);438 const receiver = await helper.eth.createAccountWithBalance(donor);382 const receiver = await helper.eth.createAccountWithBalance(donor);tests/src/rmrk/acceptNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/addResource.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/addTheme.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/burnNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/changeCollectionIssuer.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/createBase.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/createCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/deleteCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/equipNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/getOwnedNfts.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/lockCollection.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/mintNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/rejectNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/removeResource.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/rmrkIsolation.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/sendNft.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/setCollectionProperty.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/setEquippableList.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/setNftProperty.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/setResourcePriorities.seqtest.tsdiffbeforeafterbothno changes
tests/src/rmrk/util/fetch.tsdiffbeforeafterbothno changes
tests/src/rmrk/util/helpers.tsdiffbeforeafterbothno changes
tests/src/rmrk/util/tx.tsdiffbeforeafterbothno changes
tests/src/substrate/get-balance.tsdiffbeforeafterbothno changes
tests/src/substrate/privateKey.tsdiffbeforeafterbothno changes
tests/src/substrate/promisify-substrate.tsdiffbeforeafterbothno changes
tests/src/substrate/substrate-api.tsdiffbeforeafterbothno changes
tests/src/substrate/wait-new-blocks.tsdiffbeforeafterbothno changes
tests/src/transfer.nload.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {ApiPromise} from '@polkadot/api';17import os from 'os';18import {IKeyringPair} from '@polkadot/types/types';18import {IKeyringPair} from '@polkadot/types/types';19import usingApi, {submitTransactionAsync} from './substrate/substrate-api';19import {usingPlaygrounds} from './util';20import waitNewBlocks from './substrate/wait-new-blocks';20import {UniqueHelper} from './util/playgrounds/unique';21import * as cluster from 'cluster';21import * as notReallyCluster from 'cluster'; // https://github.com/nodejs/node/issues/42271#issuecomment-106341534622import os from 'os';22const cluster = notReallyCluster as unknown as notReallyCluster.Cluster;232324async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise<IKeyringPair> {24async function findUnusedAddress(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, seedAddition = ''): Promise<IKeyringPair> {25 let bal = 0n;25 let bal = 0n;26 let unused;26 let unused;27 do {27 do {28 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;28 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;29 unused = privateKeyWrapper(`//${randomSeed}`);29 unused = await privateKey(`//${randomSeed}`);30 bal = (await api.query.system.account(unused.address)).data.free.toBigInt();30 bal = await helper.balance.getSubstrate(unused.address);31 } while (bal !== 0n);31 } while (bal !== 0n);32 return unused;32 return unused;33}33}343435function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise<IKeyringPair[]> {35function findUnusedAddresses(helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, amount: number): Promise<IKeyringPair[]> {36 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now())));36 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(helper, privateKey, '_' + Date.now())));37}37}383839// Innacurate transfer fee39// Innacurate transfer fee54 counters = {};54 counters = {};55}55}565657async function distributeBalance(source: IKeyringPair, api: ApiPromise, totalAmount: bigint, stages: number) {57async function distributeBalance(source: IKeyringPair, helper: UniqueHelper, privateKey: (account: string) => Promise<IKeyringPair>, totalAmount: bigint, stages: number) {58 const accounts = [source];58 const accounts = [source];59 // we don't need source in output array59 // we don't need source in output array60 const failedAccounts = [0];60 const failedAccounts = [0];616162 const finalUserAmount = 2 ** stages - 1;62 const finalUserAmount = 2 ** stages - 1;63 accounts.push(...await findUnusedAddresses(api, finalUserAmount));63 accounts.push(...await findUnusedAddresses(helper, privateKey, finalUserAmount));64 // findUnusedAddresses produces at least 1 request per user64 // findUnusedAddresses produces at least 1 request per user65 increaseCounter('requests', finalUserAmount);65 increaseCounter('requests', finalUserAmount);666667 for (let stage = 0; stage < stages; stage++) {67 for (let stage = 0; stage < stages; stage++) {68 const usersWithBalance = 2 ** stage;68 const usersWithBalance = 2 ** stage;69 const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage);69 const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage);70 // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`);70 // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`);71 const txs = [];71 const txs: Promise<boolean | void>[] = [];72 for (let i = 0; i < usersWithBalance; i++) {72 for (let i = 0; i < usersWithBalance; i++) {73 const newUser = accounts[i + usersWithBalance];73 const newUser = accounts[i + usersWithBalance];74 // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`);74 // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`);75 const tx = api.tx.balances.transfer(newUser.address, amount);75 const tx = helper.balance.transferToSubstrate(accounts[i], newUser.address, amount);76 txs.push(submitTransactionAsync(accounts[i], tx).catch(() => {76 txs.push(tx.catch(() => {77 failedAccounts.push(i + usersWithBalance);77 failedAccounts.push(i + usersWithBalance);78 increaseCounter('txFailed', 1);78 increaseCounter('txFailed', 1);79 }));79 }));909091if (cluster.isMaster) {91if (cluster.isMaster) {92 let testDone = false;92 let testDone = false;93 usingApi(async (api) => {93 usingPlaygrounds(async (helper) => {94 const prevCounters: { [key: string]: number } = {};94 const prevCounters: { [key: string]: number } = {};95 while (!testDone) {95 while (!testDone) {96 for (const name in counters) {96 for (const name in counters) {103 console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`);103 console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`);104 prevCounters[name] = counters[name];104 prevCounters[name] = counters[name];105 }105 }106 await waitNewBlocks(api, 1);106 await helper.wait.newBlocks(1);107 }107 }108 });108 });109 const waiting: Promise<void>[] = [];109 const waiting: Promise<void>[] = [];110 console.log(`Starting ${os.cpus().length} workers`);110 console.log(`Starting ${os.cpus().length} workers`);111 usingApi(async (api, privateKeyWrapper) => {111 usingPlaygrounds(async (helper, privateKey) => {112 const alice = privateKeyWrapper('//Alice');112 const alice = await privateKey('//Alice');113 for (const id in os.cpus()) {113 for (const id in os.cpus()) {114 const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`;114 const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`;115 const workerAccount = privateKeyWrapper(WORKER_NAME);115 const workerAccount = await privateKey(WORKER_NAME);116 const tx = api.tx.balances.transfer(workerAccount.address, 400n * 10n ** 23n);116 await helper.balance.transferToSubstrate(alice, workerAccount.address, 400n * 10n ** 23n);117 await submitTransactionAsync(alice, tx);118117119 const worker = cluster.fork({118 const worker = cluster.fork({120 WORKER_NAME,119 WORKER_NAME,132 });131 });133} else {132} else {134 increaseCounter('startedWorkers', 1);133 increaseCounter('startedWorkers', 1);135 usingApi(async (api, privateKeyWrapper) => {134 usingPlaygrounds(async (helper, privateKey) => {136 await distributeBalance(privateKeyWrapper(process.env.WORKER_NAME as string), api, 400n * 10n ** 22n, 10);135 await distributeBalance(await privateKey(process.env.WORKER_NAME as string), helper, privateKey, 400n * 10n ** 22n, 10);137 });136 });138 const interval = setInterval(() => {137 const interval = setInterval(() => {139 flushCounterToMaster();138 flushCounterToMaster();