difftreelog
Merge pull request #799 from UniqueNetwork/tests/eth-helpers
in: master
14 files changed
.envdiffbeforeafterboth334POLKADOT_MAINNET_BRANCH=release-v0.9.304POLKADOT_MAINNET_BRANCH=release-v0.9.305STATEMINT_BUILD_BRANCH=release-parachains-v93205STATEMINT_BUILD_BRANCH=release-parachains-v93206ACALA_BUILD_BRANCH=2.10.16ACALA_BUILD_BRANCH=2.11.07MOONBEAM_BUILD_BRANCH=runtime-19017MOONBEAM_BUILD_BRANCH=runtime-19018UNIQUE_MAINNET_BRANCH=v9300338UNIQUE_MAINNET_BRANCH=release-v9300339UNIQUE_REPLICA_FROM=wss://eu-ws.unique.network:4439UNIQUE_REPLICA_FROM=wss://eu-ws.unique.network:443101011KUSAMA_MAINNET_BRANCH=release-v0.9.3411KUSAMA_MAINNET_BRANCH=release-v0.9.3512STATEMINE_BUILD_BRANCH=release-parachains-v932012STATEMINE_BUILD_BRANCH=release-parachains-v933013KARURA_BUILD_BRANCH=release-karura-2.10.013KARURA_BUILD_BRANCH=release-karura-2.11.014MOONRIVER_BUILD_BRANCH=runtime-190114MOONRIVER_BUILD_BRANCH=runtime-200015QUARTZ_MAINNET_BRANCH=v93003315QUARTZ_MAINNET_BRANCH=release-v93003416QUARTZ_REPLICA_FROM=wss://eu-ws-quartz.unique.network:44316QUARTZ_REPLICA_FROM=wss://eu-ws-quartz.unique.network:443171718UNQWND_MAINNET_BRANCH=release-v0.9.3018UNQWND_MAINNET_BRANCH=release-v0.9.3019WESTMINT_BUILD_BRANCH=parachains-v933019WESTMINT_BUILD_BRANCH=parachains-v933020OPAL_MAINNET_BRANCH=v93003220OPAL_MAINNET_BRANCH=release-v93003421OPAL_REPLICA_FROM=wss://eu-ws-opal.unique.network:44321OPAL_REPLICA_FROM=wss://eu-ws-opal.unique.network:443222223POLKADOT_LAUNCH_BRANCH=unique-network23POLKADOT_LAUNCH_BRANCH=unique-networktests/package.jsondiffbeforeafterboth8 "@types/chai": "^4.3.3",8 "@types/chai": "^4.3.3",9 "@types/chai-as-promised": "^7.1.5",9 "@types/chai-as-promised": "^7.1.5",10 "@types/chai-like": "^1.1.1",10 "@types/chai-like": "^1.1.1",11 "@types/chai-subset": "^1.3.3",11 "@types/mocha": "^10.0.0",12 "@types/mocha": "^10.0.0",12 "@types/node": "^18.11.2",13 "@types/node": "^18.11.2",13 "@typescript-eslint/eslint-plugin": "^5.40.1",14 "@typescript-eslint/eslint-plugin": "^5.40.1",14 "@typescript-eslint/parser": "^5.40.1",15 "@typescript-eslint/parser": "^5.40.1",15 "chai": "^4.3.6",16 "chai": "^4.3.6",17 "chai-subset": "^1.6.0",16 "eslint": "^8.25.0",18 "eslint": "^8.25.0",17 "eslint-plugin-mocha": "^10.1.0",19 "eslint-plugin-mocha": "^10.1.0",18 "mocha": "^10.1.0",20 "mocha": "^10.1.0",tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth151516import {IKeyringPair} from '@polkadot/types/types';16import {IKeyringPair} from '@polkadot/types/types';17import {expect} from 'chai';17import {expect} from 'chai';18import {Pallets} from '../util';18import {IEthCrossAccountId} from '../util/playgrounds/types';19import {IEthCrossAccountId} from '../util/playgrounds/types';19import {usingEthPlaygrounds, itEth} from './util';20import {usingEthPlaygrounds, itEth} from './util';20import {EthUniqueHelper} from './util/playgrounds/unique.dev';21import {EthUniqueHelper} from './util/playgrounds/unique.dev';39 });40 });40 });41 });414243 [44 {mode: 'nft' as const, requiredPallets: []},45 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},46 {mode: 'ft' as const, requiredPallets: []},47 ].map(testCase => {42 itEth('can add account admin by owner', async ({helper, privateKey}) => {48 itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => {43 // arrange49 // arrange44 const owner = await helper.eth.createAccountWithBalance(donor);50 const owner = await helper.eth.createAccountWithBalance(donor);45 const adminSub = await privateKey('//admin2');51 const adminSub = await privateKey('//admin2');49 const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);55 const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);50 const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);56 const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);51 57 52 const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');58 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');53 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);59 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true);546061 // Check isOwnerOrAdminCross returns false:62 expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.false;63 expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.false;64 expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.false;65 55 // Soft-deprecated: can addCollectionAdmin 66 // Soft-deprecated: can addCollectionAdmin 56 await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();67 await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();70 });81 });71 expect(adminListRpc).to.be.like(adminListEth);82 expect(adminListRpc).to.be.like(adminListEth);8384 // 3. check isOwnerOrAdminCross returns true:85 expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true;86 expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true;87 expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.true;72 });88 });89 });739074 itEth('cross account admin can mint', async ({helper}) => {91 itEth('cross account admin can mint', async ({helper}) => {75 // arrange: create collection and accounts92 // arrange: create collection and accountstests/src/eth/collectionProperties.test.tsdiffbeforeafterboth26 before(async function() {26 before(async function() {27 await usingEthPlaygrounds(async (_helper, privateKey) => {27 await usingEthPlaygrounds(async (_helper, privateKey) => {28 donor = await privateKey({filename: __filename});28 donor = await privateKey({filename: __filename});29 [alice] = await _helper.arrange.createAccounts([20n], donor);29 [alice] = await _helper.arrange.createAccounts([50n], donor);30 });30 });31 });31 });323233 // Soft-deprecated: setCollectionProperty33 // Soft-deprecated: setCollectionProperty34 [34 [35 {method: 'setCollectionProperties', methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, 35 {method: 'setCollectionProperties', mode: 'nft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, 36 {method: 'setCollectionProperties', mode: 'rft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, 37 {method: 'setCollectionProperties', mode: 'ft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, 36 {method: 'setCollectionProperty', methodParams: ['testKey', Buffer.from('testValue')], expectedProps: [{key: 'testKey', value: 'testValue'}]},38 {method: 'setCollectionProperty', mode: 'nft' as const, methodParams: ['testKey', Buffer.from('testValue')], expectedProps: [{key: 'testKey', value: 'testValue'}]},37 ].map(testCase => 39 ].map(testCase => 38 itEth(`Collection properties can be set: ${testCase.method}`, async({helper}) => {40 itEth.ifWithPallets(`Collection properties can be set: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {39 const caller = await helper.eth.createAccountWithBalance(donor);41 const caller = await helper.eth.createAccountWithBalance(donor);40 const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});42 const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []});41 await collection.addAdmin(alice, {Ethereum: caller});43 await collection.addAdmin(alice, {Ethereum: caller});4244 43 const address = helper.ethAddress.fromCollectionId(collection.collectionId);45 const address = helper.ethAddress.fromCollectionId(collection.collectionId);44 const contract = helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'setCollectionProperty');46 const collectionEvm = helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'setCollectionProperty');4748 // collectionProperties returns an empty array if no properties: 49 expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like([]);50 expect(await collectionEvm.methods.collectionProperties(['NonExistingKey']).call()).to.be.like([]);455146 await contract.methods[testCase.method](...testCase.methodParams).send({from: caller});52 await collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller});475348 const raw = (await collection.getData())?.raw;54 const raw = (await collection.getData())?.raw;49 expect(raw.properties).to.deep.equal(testCase.expectedProps);55 expect(raw.properties).to.deep.equal(testCase.expectedProps);5657 // collectionProperties returns properties: 58 expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value)));50 }));59 }));516052 itEth('Cannot set invalid properties', async({helper}) => {61 itEth('Cannot set invalid properties', async({helper}) => {687769 // Soft-deprecated: deleteCollectionProperty78 // Soft-deprecated: deleteCollectionProperty70 [79 [71 {method: 'deleteCollectionProperties', methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},80 {method: 'deleteCollectionProperties', mode: 'nft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},81 {method: 'deleteCollectionProperties', mode: 'rft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},82 {method: 'deleteCollectionProperties', mode: 'ft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]},72 {method: 'deleteCollectionProperty', methodParams: ['testKey1'], expectedProps: [{key: 'testKey2', value: 'testValue2'}, {key: 'testKey3', value: 'testValue3'}]}, 83 {method: 'deleteCollectionProperty', mode: 'nft' as const, methodParams: ['testKey1'], expectedProps: [{key: 'testKey2', value: 'testValue2'}, {key: 'testKey3', value: 'testValue3'}]}, 73 ].map(testCase => 84 ].map(testCase => 74 itEth(`Collection properties can be deleted: ${testCase.method}()`, async({helper}) => {85 itEth.ifWithPallets(`Collection properties can be deleted: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => {75 const properties = [86 const properties = [76 {key: 'testKey1', value: 'testValue1'},87 {key: 'testKey1', value: 'testValue1'},77 {key: 'testKey2', value: 'testValue2'},88 {key: 'testKey2', value: 'testValue2'},78 {key: 'testKey3', value: 'testValue3'}];89 {key: 'testKey3', value: 'testValue3'}];79 const caller = await helper.eth.createAccountWithBalance(donor);90 const caller = await helper.eth.createAccountWithBalance(donor);80 const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});91 const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties});81 92 82 await collection.addAdmin(alice, {Ethereum: caller});93 await collection.addAdmin(alice, {Ethereum: caller});83 94 210 }));220 }));211});221});212213describe('EVM collection property', () => {214 let donor: IKeyringPair;215216 before(async function() {217 await usingEthPlaygrounds(async (_helper, privateKey) => {218 donor = await privateKey({filename: __filename});219 });220 });221222 [223 {case: 'nft' as const},224 {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},225 {case: 'ft' as const},226 ].map(testCase => 227 itEth.ifWithPallets(`can set/read properties ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {228 const collection = await helper[testCase.case].mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});229230 const sender = await helper.eth.createAccountWithBalance(donor, 100n);231 await collection.addAdmin(donor, {Ethereum: sender});232 233 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);234 const contract = helper.ethNativeContract.collection(collectionAddress, testCase.case, sender);235 236 const keys = ['key0', 'key1'];237 238 const writeProperties = [239 helper.ethProperty.property(keys[0], 'value0'),240 helper.ethProperty.property(keys[1], 'value1'),241 ];242 243 await contract.methods.setCollectionProperties(writeProperties).send();244 const readProperties = await contract.methods.collectionProperties([keys[0], keys[1]]).call();245 expect(readProperties).to.be.like(writeProperties);246 }));247248 [249 {case: 'nft' as const},250 {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]},251 {case: 'ft' as const},252 ].map(testCase => 253 itEth.ifWithPallets(`can delete properties ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => {254 const collection = await helper[testCase.case].mintCollection(donor, {name: 'A', description: 'B', tokenPrefix: 'C'});255256 const sender = await helper.eth.createAccountWithBalance(donor, 100n);257 await collection.addAdmin(donor, {Ethereum: sender});258 259 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);260 const contract = helper.ethNativeContract.collection(collectionAddress, testCase.case, sender);261 262 const keys = ['key0', 'key1', 'key2', 'key3'];263 264 {265 const writeProperties = [266 helper.ethProperty.property(keys[0], 'value0'),267 helper.ethProperty.property(keys[1], 'value1'),268 helper.ethProperty.property(keys[2], 'value2'),269 helper.ethProperty.property(keys[3], 'value3'),270 ];271 272 await contract.methods.setCollectionProperties(writeProperties).send();273 const readProperties = await contract.methods.collectionProperties([keys[0], keys[1], keys[2], keys[3]]).call();274 expect(readProperties).to.be.like(writeProperties);275 }276 277 {278 const expectProperties = [279 helper.ethProperty.property(keys[0], 'value0'),280 helper.ethProperty.property(keys[1], 'value1'),281 ];282 283 await contract.methods.deleteCollectionProperties([keys[2], keys[3]]).send();284 const readProperties = await contract.methods.collectionProperties([]).call();285 expect(readProperties).to.be.like(expectProperties);286 }287 }));288});289222tests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth222223describe('Sponsoring EVM contracts', () => {23describe('Sponsoring EVM contracts', () => {24 let donor: IKeyringPair;24 let donor: IKeyringPair;25 let nominal: bigint;252626 before(async () => {27 before(async () => {27 await usingPlaygrounds(async (_helper, privateKey) => {28 await usingPlaygrounds(async (helper, privateKey) => {28 donor = await privateKey({filename: __filename});29 donor = await privateKey({filename: __filename});30 nominal = helper.balance.getOneTokenNominal();29 });31 });30 });32 });3132 itEth('Self sponsored can be set by the address that deployed the contract', async ({helper}) => {33 const owner = await helper.eth.createAccountWithBalance(donor);34 const flipper = await helper.eth.deployFlipper(owner);35 const helpers = helper.ethNativeContract.contractHelpers(owner);3637 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;38 await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected;39 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;40 });413342 itEth('Set self sponsored events', async ({helper}) => {34 itEth('Self sponsoring can be set by the address that deployed the contract', async ({helper}) => {43 const owner = await helper.eth.createAccountWithBalance(donor);35 const owner = await helper.eth.createAccountWithBalance(donor);44 const flipper = await helper.eth.deployFlipper(owner);36 const flipper = await helper.eth.deployFlipper(owner);45 const helpers = helper.ethNativeContract.contractHelpers(owner);37 const helpers = helper.ethNativeContract.contractHelpers(owner);46 3839 // 1. owner can set selfSponsoring:40 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;47 const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send();41 const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send({from: owner});42 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;4344 // 1.1 Can get sponsor using methods.sponsor:45 const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call();46 expect(actualSponsor.eth).to.eq(flipper.options.address);47 expect(actualSponsor.sub).to.eq('0');4849 // 2. Events should be:48 const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events);50 const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events);49 expect(ethEvents).to.be.deep.equal([51 expect(ethEvents).to.be.deep.equal([50 {52 {66 ]);68 ]);67 });69 });687069 itEth('Self sponsored can not be set by the address that did not deployed the contract', async ({helper}) => {71 itEth('Self sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => {70 const owner = await helper.eth.createAccountWithBalance(donor);72 const owner = await helper.eth.createAccountWithBalance(donor);71 const notOwner = await helper.eth.createAccountWithBalance(donor);73 const notOwner = await helper.eth.createAccountWithBalance(donor);72 const helpers = helper.ethNativeContract.contractHelpers(owner);74 const helpers = helper.ethNativeContract.contractHelpers(owner);83 const flipper = await helper.eth.deployFlipper(owner);85 const flipper = await helper.eth.deployFlipper(owner);848685 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;87 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;86 await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected;88 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});87 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;89 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;88 });90 });899198 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;100 expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;99 });101 });100 102 101 itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => {102 const owner = await helper.eth.createAccountWithBalance(donor);103 const sponsor = await helper.eth.createAccountWithBalance(donor);104 const helpers = helper.ethNativeContract.contractHelpers(owner);105 const flipper = await helper.eth.deployFlipper(owner);106107 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;108 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;109 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;110 });111 112 itEth('Set sponsor event', async ({helper}) => {103 itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => {113 const owner = await helper.eth.createAccountWithBalance(donor);104 const owner = await helper.eth.createAccountWithBalance(donor);114 const sponsor = await helper.eth.createAccountWithBalance(donor);105 const sponsor = await helper.eth.createAccountWithBalance(donor);115 const helpers = helper.ethNativeContract.contractHelpers(owner);106 const helpers = helper.ethNativeContract.contractHelpers(owner);116 const flipper = await helper.eth.deployFlipper(owner);107 const flipper = await helper.eth.deployFlipper(owner);117 108109 // 1. owner can set a sponsor:110 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;118 const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();111 const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send();112 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true;113114 // 2. Events should be:119 const events = helper.eth.normalizeEvents(result.events);115 const events = helper.eth.normalizeEvents(result.events);120 expect(events).to.be.deep.equal([116 expect(events).to.be.deep.equal([121 {117 {129 ]);125 ]);130 });126 });131 127 132 itEth('Sponsor can not be set by the address that did not deployed the contract', async ({helper}) => {128 itEth('Sponsor cannot be set by the address that did not deployed the contract', async ({helper}) => {133 const owner = await helper.eth.createAccountWithBalance(donor);129 const owner = await helper.eth.createAccountWithBalance(donor);134 const sponsor = await helper.eth.createAccountWithBalance(donor);130 const sponsor = await helper.eth.createAccountWithBalance(donor);135 const notOwner = await helper.eth.createAccountWithBalance(donor);131 const notOwner = await helper.eth.createAccountWithBalance(donor);141 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;137 expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false;142 });138 });143144 itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => {145 const owner = await helper.eth.createAccountWithBalance(donor);146 const sponsor = await helper.eth.createAccountWithBalance(donor);147 const helpers = helper.ethNativeContract.contractHelpers(owner);148 const flipper = await helper.eth.deployFlipper(owner);149150 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;151 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;152 await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected;153 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;154 });155139156 itEth('Confirm sponsorship event', async ({helper}) => {140 itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => {157 const owner = await helper.eth.createAccountWithBalance(donor);141 const owner = await helper.eth.createAccountWithBalance(donor);158 const sponsor = await helper.eth.createAccountWithBalance(donor);142 const sponsor = await helper.eth.createAccountWithBalance(donor);159 const helpers = helper.ethNativeContract.contractHelpers(owner);143 const helpers = helper.ethNativeContract.contractHelpers(owner);160 const flipper = await helper.eth.deployFlipper(owner);144 const flipper = await helper.eth.deployFlipper(owner);161145146 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;162 await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected;147 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();148149 // 1. sponsor can confirm sponsorship:163 const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});150 const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});151 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;152153 // 1.1 Can get sponsor using methods.sponsor:154 const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call();155 expect(actualSponsor.eth).to.eq(sponsor);156 expect(actualSponsor.sub).to.eq('0');157158 // 2. Events should be:164 const events = helper.eth.normalizeEvents(result.events);159 const events = helper.eth.normalizeEvents(result.events);165 expect(events).to.be.deep.equal([160 expect(events).to.be.deep.equal([166 {161 {198 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;193 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;199 });194 });200201 itEth('Get self sponsored sponsor', async ({helper}) => {202 const owner = await helper.eth.createAccountWithBalance(donor);203 const helpers = helper.ethNativeContract.contractHelpers(owner);204 const flipper = await helper.eth.deployFlipper(owner);205206 await helpers.methods.selfSponsoredEnable(flipper.options.address).send();207 208 const result = await helpers.methods.sponsor(flipper.options.address).call();209210 expect(result[0]).to.be.eq(flipper.options.address);211 expect(result[1]).to.be.eq('0');212 });213214 itEth('Get confirmed sponsor', async ({helper}) => {215 const owner = await helper.eth.createAccountWithBalance(donor);216 const sponsor = await helper.eth.createAccountWithBalance(donor);217 const helpers = helper.ethNativeContract.contractHelpers(owner);218 const flipper = await helper.eth.deployFlipper(owner);219220 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();221 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});222 223 const result = await helpers.methods.sponsor(flipper.options.address).call();224225 expect(result[0]).to.be.eq(sponsor);226 expect(result[1]).to.be.eq('0');227 });228195229 itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => {196 itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => {230 const owner = await helper.eth.createAccountWithBalance(donor);197 const owner = await helper.eth.createAccountWithBalance(donor);236 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();203 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();237 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});204 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});238 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;205 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;239 206 // 1. Can remove sponsor:240 await helpers.methods.removeSponsor(flipper.options.address).send();207 const result = await helpers.methods.removeSponsor(flipper.options.address).send();241 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;208 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false;209210 // 2. Events should be:211 const events = helper.eth.normalizeEvents(result.events);212 expect(events).to.be.deep.equal([213 {214 address: flipper.options.address,215 event: 'ContractSponsorRemoved',216 args: {217 contractAddress: flipper.options.address,218 },219 },220 ]);221222 // TODO: why call method reverts?223 // const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call();224 // expect(actualSponsor.eth).to.eq(sponsor);225 // expect(actualSponsor.sub).to.eq('0');242 });226 });243244 itEth('Remove sponsor event', async ({helper}) => {245 const owner = await helper.eth.createAccountWithBalance(donor);246 const sponsor = await helper.eth.createAccountWithBalance(donor);247 const helpers = helper.ethNativeContract.contractHelpers(owner);248 const flipper = await helper.eth.deployFlipper(owner);249250 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();251 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});252 253 const result = await helpers.methods.removeSponsor(flipper.options.address).send();254 const events = helper.eth.normalizeEvents(result.events);255 expect(events).to.be.deep.equal([256 {257 address: flipper.options.address,258 event: 'ContractSponsorRemoved',259 args: {260 contractAddress: flipper.options.address,261 },262 },263 ]);264 });265227266 itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => {228 itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => {267 const owner = await helper.eth.createAccountWithBalance(donor);229 const owner = await helper.eth.createAccountWithBalance(donor);276 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;238 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;277 239 278 await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');240 await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission');241 await expect(helpers.methods.removeSponsor(flipper.options.address).send({from: notOwner})).to.be.rejected;279 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;242 expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true;280 });243 });281244292 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});255 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});293 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});256 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});294257295 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));258 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));296 const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));259 const callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));297260298 await flipper.methods.flip().send({from: caller});261 await flipper.methods.flip().send({from: caller});299 expect(await flipper.methods.getValue().call()).to.be.true;262 expect(await flipper.methods.getValue().call()).to.be.true;300263301 // Balance should be taken from sponsor instead of caller264 // Balance should be taken from sponsor instead of caller302 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));265 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));303 const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));266 const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));304 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;267 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;305 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);268 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);306 });269 });331 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);294 expect(callerBalanceAfter).to.be.eq(callerBalanceBefore);332 });295 });333296297 [298 {balance: 0n, label: '0'},299 {balance: 10n, label: '10'},300 ].map(testCase => {334 itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({helper}) => {301 itEth(`Allow-listed address that has ${testCase.label} UNQ can call a contract. Sponsor balance should decrease`, async ({helper}) => {335 const owner = await helper.eth.createAccountWithBalance(donor);302 const owner = await helper.eth.createAccountWithBalance(donor);336 const sponsor = await helper.eth.createAccountWithBalance(donor);303 const sponsor = await helper.eth.createAccountWithBalance(donor);337 const caller = helper.eth.createAccount();304 const caller = helper.eth.createAccount();305 await helper.eth.transferBalanceFromSubstrate(donor, caller, testCase.balance);338 const helpers = helper.ethNativeContract.contractHelpers(owner);306 const helpers = helper.ethNativeContract.contractHelpers(owner);339 const flipper = await helper.eth.deployFlipper(owner);307 const flipper = await helper.eth.deployFlipper(owner);340308 347 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();315 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();348 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});316 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});349317 350 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));318 const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));351 expect(sponsorBalanceBefore).to.be.not.equal('0');319 expect(sponsorBalanceBefore > 0n).to.be.true;352320 353 await flipper.methods.flip().send({from: caller});321 await flipper.methods.flip().send({from: caller});354 expect(await flipper.methods.getValue().call()).to.be.true;322 expect(await flipper.methods.getValue().call()).to.be.true;355323 356 // Balance should be taken from flipper instead of caller324 // Balance should be taken from flipper instead of caller357 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));325 const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor));358 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;326 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;327 // Caller's balance does not change:328 const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller));329 expect(callerBalanceAfter).to.eq(testCase.balance * nominal);359 });330 });360331 });361 itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({helper}) => {362 const owner = await helper.eth.createAccountWithBalance(donor);363 const caller = await helper.eth.createAccount();364 const helpers = helper.ethNativeContract.contractHelpers(owner);365 const flipper = await helper.eth.deployFlipper(owner);366367 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});368 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});369370 await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);371372 const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);373 expect(originalFlipperBalance).to.be.not.equal('0');374375 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/);376 expect(await flipper.methods.getValue().call()).to.be.false;377378 // Balance should be taken from flipper instead of caller379 // FIXME the comment is wrong! What check should be here?380 const balanceAfter = await helper.balance.getEthereum(flipper.options.address);381 expect(balanceAfter).to.be.equal(originalFlipperBalance);382 });383332384 itEth('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({helper}) => {333 itEth('Non-allow-listed address can call a contract. Sponsor balance should not decrease', async ({helper}) => {385 const owner = await helper.eth.createAccountWithBalance(donor);334 const owner = await helper.eth.createAccountWithBalance(donor);386 const sponsor = await helper.eth.createAccountWithBalance(donor);387 const caller = await helper.eth.createAccountWithBalance(donor);335 const caller = helper.eth.createAccount();388 const helpers = helper.ethNativeContract.contractHelpers(owner);336 const contractHelpers = helper.ethNativeContract.contractHelpers(owner);337338 // Deploy flipper and send some tokens:389 const flipper = await helper.eth.deployFlipper(owner);339 const flipper = await helper.eth.deployFlipper(owner);390391 await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});340 await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address);392 await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});341 expect(await flipper.methods.getValue().call()).to.be.false;393342 // flipper address has some tokens:394 await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});343 const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);344 expect(originalFlipperBalance > 0n).to.be.true;345346 // Set Allowlisted sponsoring mode. caller is not in allow list:395 await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});347 await contractHelpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});396397 await helpers.methods.setSponsor(flipper.options.address, sponsor).send();348 await contractHelpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});398 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});349 await contractHelpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});399350400 const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));351 // 1. Caller has no UNQ and is not in allow list. So he cannot flip: 401 const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));402403 await flipper.methods.flip().send({from: caller});352 await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/);404 expect(await flipper.methods.getValue().call()).to.be.true;353 expect(await flipper.methods.getValue().call()).to.be.false;405354355 // Flipper's balance does not change:406 const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor));356 const balanceAfter = await helper.balance.getEthereum(flipper.options.address);407 const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller));408 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;409 expect(callerBalanceAfter).to.be.equal(callerBalanceBefore);357 expect(balanceAfter).to.be.equal(originalFlipperBalance);410 });358 });411359412 itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => {360 itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => {427 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});375 await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor});428376429 const originalFlipperBalance = await helper.balance.getEthereum(sponsor);377 const originalFlipperBalance = await helper.balance.getEthereum(sponsor);430 expect(originalFlipperBalance).to.be.not.equal('0');378 expect(originalFlipperBalance > 0n).to.be.true;431379432 await flipper.methods.flip().send({from: caller});380 await flipper.methods.flip().send({from: caller});433 expect(await flipper.methods.getValue().call()).to.be.true;381 expect(await flipper.methods.getValue().call()).to.be.true;tests/src/eth/events.test.tsdiffbeforeafterboth40 const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');40 const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');41 await helper.wait.newBlocks(1);41 await helper.wait.newBlocks(1);42 {42 {43 expect(ethEvents).to.be.like([43 expect(ethEvents).to.containSubset([44 {44 {45 event: 'CollectionCreated',45 event: 'CollectionCreated',46 args: {46 args: {49 },49 },50 },50 },51 ]);51 ]);52 expect(subEvents).to.be.like([{method: 'CollectionCreated'}]);52 expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]);53 clearEvents(ethEvents, subEvents);53 clearEvents(ethEvents, subEvents);54 }54 }55 {55 {56 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);56 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);57 const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});57 const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner});58 await helper.wait.newBlocks(1);58 await helper.wait.newBlocks(1);59 expect(result.events).to.be.like({59 expect(result.events).to.containSubset({60 CollectionDestroyed: {60 CollectionDestroyed: {61 returnValues: {61 returnValues: {62 collectionId: collectionAddress,62 collectionId: collectionAddress,63 },63 },64 },64 },65 });65 });66 expect(subEvents).to.be.like([{method: 'CollectionDestroyed'}]);66 expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]);67 }67 }68 unsubscribe();68 unsubscribe();69}69}707071async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {71async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {72 const owner = await helper.eth.createAccountWithBalance(donor);72 const owner = await helper.eth.createAccountWithBalance(donor);73 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');73 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');74 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);74 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);75 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);75 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);76 76 77 const ethEvents: any = [];77 const ethEvents: any = [];82 {82 {83 await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});83 await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner});84 await helper.wait.newBlocks(1);84 await helper.wait.newBlocks(1);85 expect(ethEvents).to.be.like([85 expect(ethEvents).to.containSubset([86 {86 {87 event: 'CollectionChanged',87 event: 'CollectionChanged',88 returnValues: {88 returnValues: {89 collectionId: collectionAddress,89 collectionId: collectionAddress,90 },90 },91 },91 },92 ]);92 ]);93 expect(subEvents).to.be.like([{method: 'CollectionPropertySet'}]);93 expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]);94 clearEvents(ethEvents, subEvents);94 clearEvents(ethEvents, subEvents);95 }95 }96 {96 {97 await collection.methods.deleteCollectionProperties(['A']).send({from:owner});97 await collection.methods.deleteCollectionProperties(['A']).send({from:owner});98 await helper.wait.newBlocks(1);98 await helper.wait.newBlocks(1);99 expect(ethEvents).to.be.like([99 expect(ethEvents).to.containSubset([100 {100 {101 event: 'CollectionChanged',101 event: 'CollectionChanged',102 returnValues: {102 returnValues: {103 collectionId: collectionAddress,103 collectionId: collectionAddress,104 },104 },105 },105 },106 ]);106 ]);107 expect(subEvents).to.be.like([{method: 'CollectionPropertyDeleted'}]);107 expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]);108 }108 }109 unsubscribe();109 unsubscribe();110}110}111111112async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {112async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {113 const owner = await helper.eth.createAccountWithBalance(donor);113 const owner = await helper.eth.createAccountWithBalance(donor);114 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');114 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');115 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);115 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);116 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);116 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);117 const ethEvents: any = [];117 const ethEvents: any = [];118 collectionHelper.events.allEvents((_: any, event: any) => {118 collectionHelper.events.allEvents((_: any, event: any) => {127 ],127 ],128 ]).send({from: owner});128 ]).send({from: owner});129 await helper.wait.newBlocks(1);129 await helper.wait.newBlocks(1);130 expect(ethEvents).to.be.like([130 expect(ethEvents).to.containSubset([131 {131 {132 event: 'CollectionChanged',132 event: 'CollectionChanged',133 returnValues: {133 returnValues: {134 collectionId: collectionAddress,134 collectionId: collectionAddress,135 },135 },136 },136 },137 ]);137 ]);138 expect(subEvents).to.be.like([{method: 'PropertyPermissionSet'}]);138 expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]);139 unsubscribe();139 unsubscribe();140}140}141141142async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {142async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) {143 const owner = await helper.eth.createAccountWithBalance(donor);143 const owner = await helper.eth.createAccountWithBalance(donor);144 const user = helper.ethCrossAccount.createAccount();144 const user = helper.ethCrossAccount.createAccount();145 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');145 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');146 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);146 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);147 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);147 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);148 const ethEvents: any[] = [];148 const ethEvents: any[] = [];149 collectionHelper.events.allEvents((_: any, event: any) => {149 collectionHelper.events.allEvents((_: any, event: any) => {154 {154 {155 await collection.methods.addToCollectionAllowListCross(user).send({from: owner});155 await collection.methods.addToCollectionAllowListCross(user).send({from: owner});156 await helper.wait.newBlocks(1);156 await helper.wait.newBlocks(1);157 expect(ethEvents).to.be.like([157 expect(ethEvents).to.containSubset([158 {158 {159 event: 'CollectionChanged',159 event: 'CollectionChanged',160 returnValues: {160 returnValues: {161 collectionId: collectionAddress,161 collectionId: collectionAddress,162 },162 },163 },163 },164 ]);164 ]);165 expect(subEvents).to.be.like([{method: 'AllowListAddressAdded'}]);165 expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]);166 clearEvents(ethEvents, subEvents);166 clearEvents(ethEvents, subEvents);167 }167 }168 {168 {169 await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});169 await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner});170 await helper.wait.newBlocks(1);170 await helper.wait.newBlocks(1);171 expect(ethEvents.length).to.be.eq(1);172 expect(ethEvents).to.be.like([171 expect(ethEvents).to.containSubset([173 {172 {174 event: 'CollectionChanged',173 event: 'CollectionChanged',175 returnValues: {174 returnValues: {176 collectionId: collectionAddress,175 collectionId: collectionAddress,177 },176 },178 },177 },179 ]);178 ]);180 expect(subEvents).to.be.like([{method: 'AllowListAddressRemoved'}]);179 expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]);181 }180 }182 unsubscribe();181 unsubscribe();183}182}186 const owner = await helper.eth.createAccountWithBalance(donor);185 const owner = await helper.eth.createAccountWithBalance(donor);187 const user = helper.ethCrossAccount.createAccount();186 const user = helper.ethCrossAccount.createAccount();188 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');187 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');189 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);188 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);190 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);189 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);191 const ethEvents: any = [];190 const ethEvents: any = [];192 collectionHelper.events.allEvents((_: any, event: any) => {191 collectionHelper.events.allEvents((_: any, event: any) => {196 {195 {197 await collection.methods.addCollectionAdminCross(user).send({from: owner});196 await collection.methods.addCollectionAdminCross(user).send({from: owner});198 await helper.wait.newBlocks(1);197 await helper.wait.newBlocks(1);199 expect(ethEvents).to.be.like([198 expect(ethEvents).to.containSubset([200 {199 {201 event: 'CollectionChanged',200 event: 'CollectionChanged',202 returnValues: {201 returnValues: {203 collectionId: collectionAddress,202 collectionId: collectionAddress,204 },203 },205 },204 },206 ]);205 ]);207 expect(subEvents).to.be.like([{method: 'CollectionAdminAdded'}]);206 expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]);208 clearEvents(ethEvents, subEvents);207 clearEvents(ethEvents, subEvents);209 }208 }210 {209 {211 await collection.methods.removeCollectionAdminCross(user).send({from: owner});210 await collection.methods.removeCollectionAdminCross(user).send({from: owner});212 await helper.wait.newBlocks(1);211 await helper.wait.newBlocks(1);213 expect(ethEvents).to.be.like([212 expect(ethEvents).to.containSubset([214 {213 {215 event: 'CollectionChanged',214 event: 'CollectionChanged',216 returnValues: {215 returnValues: {217 collectionId: collectionAddress,216 collectionId: collectionAddress,218 },217 },219 },218 },220 ]);219 ]);221 expect(subEvents).to.be.like([{method: 'CollectionAdminRemoved'}]);220 expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]);222 }221 }223 unsubscribe();222 unsubscribe();224}223}225224226async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {225async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) {227 const owner = await helper.eth.createAccountWithBalance(donor);226 const owner = await helper.eth.createAccountWithBalance(donor);228 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');227 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');229 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);228 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);230 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);229 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);231 const ethEvents: any = [];230 const ethEvents: any = [];232 collectionHelper.events.allEvents((_: any, event: any) => {231 collectionHelper.events.allEvents((_: any, event: any) => {236 {235 {237 await collection.methods.setCollectionLimit(CollectionLimits.OwnerCanTransfer, true, 0).send({from: owner});236 await collection.methods.setCollectionLimit(CollectionLimits.OwnerCanTransfer, true, 0).send({from: owner});238 await helper.wait.newBlocks(1);237 await helper.wait.newBlocks(1);239 expect(ethEvents).to.be.like([238 expect(ethEvents).to.containSubset([240 {239 {241 event: 'CollectionChanged',240 event: 'CollectionChanged',242 returnValues: {241 returnValues: {243 collectionId: collectionAddress,242 collectionId: collectionAddress,244 },243 },245 },244 },246 ]);245 ]);247 expect(subEvents).to.be.like([{method: 'CollectionLimitSet'}]);246 expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]);248 }247 }249 unsubscribe();248 unsubscribe();250}249}253 const owner = await helper.eth.createAccountWithBalance(donor);252 const owner = await helper.eth.createAccountWithBalance(donor);254 const newOwner = helper.ethCrossAccount.createAccount();253 const newOwner = helper.ethCrossAccount.createAccount();255 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');254 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');256 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);255 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);257 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);256 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);258 const ethEvents: any = [];257 const ethEvents: any = [];259 collectionHelper.events.allEvents((_: any, event: any) => {258 collectionHelper.events.allEvents((_: any, event: any) => {263 {262 {264 await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});263 await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner});265 await helper.wait.newBlocks(1);264 await helper.wait.newBlocks(1);266 expect(ethEvents).to.be.like([265 expect(ethEvents).to.containSubset([267 {266 {268 event: 'CollectionChanged',267 event: 'CollectionChanged',269 returnValues: {268 returnValues: {270 collectionId: collectionAddress,269 collectionId: collectionAddress,271 },270 },272 },271 },273 ]);272 ]);274 expect(subEvents).to.be.like([{method: 'CollectionOwnerChanged'}]);273 expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]);275 }274 }276 unsubscribe();275 unsubscribe();277}276}278277279async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {278async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) {280 const owner = await helper.eth.createAccountWithBalance(donor);279 const owner = await helper.eth.createAccountWithBalance(donor);281 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');280 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');282 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);281 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);283 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);282 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);284 const ethEvents: any = [];283 const ethEvents: any = [];285 collectionHelper.events.allEvents((_: any, event: any) => {284 collectionHelper.events.allEvents((_: any, event: any) => {289 {288 {290 await collection.methods.setCollectionMintMode(true).send({from: owner});289 await collection.methods.setCollectionMintMode(true).send({from: owner});291 await helper.wait.newBlocks(1);290 await helper.wait.newBlocks(1);292 expect(ethEvents).to.be.like([291 expect(ethEvents).to.containSubset([293 {292 {294 event: 'CollectionChanged',293 event: 'CollectionChanged',295 returnValues: {294 returnValues: {296 collectionId: collectionAddress,295 collectionId: collectionAddress,297 },296 },298 },297 },299 ]);298 ]);300 expect(subEvents).to.be.like([{method: 'CollectionPermissionSet'}]);299 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);301 clearEvents(ethEvents, subEvents);300 clearEvents(ethEvents, subEvents);302 }301 }303 {302 {304 await collection.methods.setCollectionAccess(1).send({from: owner});303 await collection.methods.setCollectionAccess(1).send({from: owner});305 await helper.wait.newBlocks(1);304 await helper.wait.newBlocks(1);306 expect(ethEvents).to.be.like([305 expect(ethEvents).to.containSubset([307 {306 {308 event: 'CollectionChanged',307 event: 'CollectionChanged',309 returnValues: {308 returnValues: {310 collectionId: collectionAddress,309 collectionId: collectionAddress,311 },310 },312 },311 },313 ]);312 ]);314 expect(subEvents).to.be.like([{method: 'CollectionPermissionSet'}]);313 expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]);315 }314 }316 unsubscribe();315 unsubscribe();317}316}320 const owner = await helper.eth.createAccountWithBalance(donor);319 const owner = await helper.eth.createAccountWithBalance(donor);321 const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);320 const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor);322 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');321 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');323 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);322 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);324 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);323 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);325 const ethEvents: any = [];324 const ethEvents: any = [];326 collectionHelper.events.allEvents((_: any, event: any) => {325 collectionHelper.events.allEvents((_: any, event: any) => {332 {331 {333 await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});332 await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner});334 await helper.wait.newBlocks(1);333 await helper.wait.newBlocks(1);335 expect(ethEvents).to.be.like([334 expect(ethEvents).to.containSubset([{336 {337 event: 'CollectionChanged',335 event: 'CollectionChanged',338 returnValues: {336 returnValues: {339 collectionId: collectionAddress,337 collectionId: collectionAddress,340 },338 },341 },339 }]);342 ]);343 expect(subEvents).to.be.like([{method: 'CollectionSponsorSet'}]);340 expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]);344 clearEvents(ethEvents, subEvents);341 clearEvents(ethEvents, subEvents);345 }342 }346 {343 {347 await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});344 await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth});348 await helper.wait.newBlocks(1);345 await helper.wait.newBlocks(1);349 expect(ethEvents).to.be.like([346 expect(ethEvents).to.containSubset([350 {347 {351 event: 'CollectionChanged',348 event: 'CollectionChanged',352 returnValues: {349 returnValues: {353 collectionId: collectionAddress,350 collectionId: collectionAddress,354 },351 },355 },352 },356 ]);353 ]);357 expect(subEvents).to.be.like([{method: 'SponsorshipConfirmed'}]);354 expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]);358 clearEvents(ethEvents, subEvents);355 clearEvents(ethEvents, subEvents);359 }356 }360 {357 {361 await collection.methods.removeCollectionSponsor().send({from: owner});358 await collection.methods.removeCollectionSponsor().send({from: owner});362 await helper.wait.newBlocks(1);359 await helper.wait.newBlocks(1);363 expect(ethEvents).to.be.like([360 expect(ethEvents).to.containSubset([364 {361 {365 event: 'CollectionChanged',362 event: 'CollectionChanged',366 returnValues: {363 returnValues: {367 collectionId: collectionAddress,364 collectionId: collectionAddress,368 },365 },369 },366 },370 ]);367 ]);371 expect(subEvents).to.be.like([{method: 'CollectionSponsorRemoved'}]);368 expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]);372 }369 }373 unsubscribe();370 unsubscribe();374}371}375372376async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {373async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) {377 const owner = await helper.eth.createAccountWithBalance(donor);374 const owner = await helper.eth.createAccountWithBalance(donor);378 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');375 const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C');379 const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner);376 const collection = helper.ethNativeContract.collection(collectionAddress, mode, owner);380 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);377 const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);381 const result = await collection.methods.mint(owner).send({from: owner});378 const result = await collection.methods.mint(owner).send({from: owner});382 const tokenId = result.events.Transfer.returnValues.tokenId;379 const tokenId = result.events.Transfer.returnValues.tokenId;397 {394 {398 await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});395 await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner});399 await helper.wait.newBlocks(1);396 await helper.wait.newBlocks(1);400 expect(ethEvents).to.be.like([397 expect(ethEvents).to.containSubset([401 {398 {402 event: 'TokenChanged',399 event: 'TokenChanged',403 returnValues: {400 returnValues: {404 collectionId: collectionAddress,401 collectionId: collectionAddress,405 },402 },406 },403 },407 ]);404 ]);408 expect(subEvents).to.be.like([{method: 'TokenPropertySet'}]);405 expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]);409 clearEvents(ethEvents, subEvents);406 clearEvents(ethEvents, subEvents);410 }407 }411 {408 {412 await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});409 await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});413 await helper.wait.newBlocks(1);410 await helper.wait.newBlocks(1);414 expect(ethEvents).to.be.like([411 expect(ethEvents).to.containSubset([415 {412 {416 event: 'TokenChanged',413 event: 'TokenChanged',417 returnValues: {414 returnValues: {418 collectionId: collectionAddress,415 collectionId: collectionAddress,419 },416 },420 },417 },421 ]);418 ]);422 expect(subEvents).to.be.like([{method: 'TokenPropertyDeleted'}]);419 expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]);423 }420 }424 unsubscribe();421 unsubscribe();425}422}tests/src/eth/fungible.test.tsdiffbeforeafterboth79 expect(event.returnValues.value).to.equal('100');79 expect(event.returnValues.value).to.equal('100');80 });80 });81 81 82 82 [83 'substrate' as const,84 'ethereum' as const,85 ].map(testCase => {83 itEth('Can perform mintCross()', async ({helper}) => {86 itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {87 // 1. Create receiver depending on the test case:88 const receiverEth = helper.eth.createAccount();89 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);90 const receiverSub = owner;84 const receiverCross = helper.ethCrossAccount.fromKeyringPair(owner);91 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(owner);9285 const ethOwner = await helper.eth.createAccountWithBalance(donor);93 const ethOwner = await helper.eth.createAccountWithBalance(donor);86 const collection = await helper.ft.mintCollection(alice);94 const collection = await helper.ft.mintCollection(alice);87 await collection.addAdmin(alice, {Ethereum: ethOwner});95 await collection.addAdmin(alice, {Ethereum: ethOwner});8896 89 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);97 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);90 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);98 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner);9199 100 // 2. Mint tokens:92 const result = await contract.methods.mintCross(receiverCross, 100).send();101 const result = await collectionEvm.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, 100).send();93 102 94 const event = result.events.Transfer;103 const event = result.events.Transfer;95 expect(event.address).to.equal(collectionAddress);104 expect(event.address).to.equal(collectionAddress);96 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');105 expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000');97 expect(event.returnValues.to).to.equal(helper.address.substrateToEth(owner.address));106 expect(event.returnValues.to).to.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(receiverSub.address));98 expect(event.returnValues.value).to.equal('100');107 expect(event.returnValues.value).to.equal('100');108109 // 3. Get balance depending on the test case:110 let balance;111 if (testCase === 'ethereum') balance = await collection.getBalance({Ethereum: receiverEth});112 else if (testCase === 'substrate') balance = await collection.getBalance({Substrate: receiverSub.address});113 // 3.1 Check balance:114 expect(balance).to.eq(100n);99 });115 });116 });100117101 itEth('Can perform mintBulk()', async ({helper}) => {118 itEth('Can perform mintBulk()', async ({helper}) => {102 const owner = await helper.eth.createAccountWithBalance(donor);119 const owner = await helper.eth.createAccountWithBalance(donor);169 }186 }170 });187 });188189 itEth('Can perform approveCross()', async ({helper}) => {190 const owner = await helper.eth.createAccountWithBalance(donor);191 const spender = helper.eth.createAccount();192 const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0];193 const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender);194 const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub);195 196197 const collection = await helper.ft.mintCollection(alice);198 await collection.mint(alice, 200n, {Ethereum: owner});199200 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);201 const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);202203 {204 const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner});205 const event = result.events.Approval;206 expect(event.address).to.be.equal(collectionAddress);207 expect(event.returnValues.owner).to.be.equal(owner);208 expect(event.returnValues.spender).to.be.equal(spender);209 expect(event.returnValues.value).to.be.equal('100');210 }211212 {213 const allowance = await contract.methods.allowance(owner, spender).call();214 expect(+allowance).to.equal(100);215 }216 217 218 {219 const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner});220 const event = result.events.Approval;221 expect(event.address).to.be.equal(collectionAddress);222 expect(event.returnValues.owner).to.be.equal(owner);223 expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address));224 expect(event.returnValues.value).to.be.equal('100');225 }226227 {228 const allowance = await collection.getApprovedTokens({Ethereum: owner}, {Substrate: spenderSub.address});229 expect(allowance).to.equal(100n);230 }231 232 {233 //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call()234 }235 });236237 itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {238 const nonOwner = await helper.eth.createAccountWithBalance(donor);239 const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);240 const owner = await helper.eth.createAccountWithBalance(donor);241 const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});242 await collection.mint(alice, 100n, {Ethereum: owner});243244 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);245 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);246247 await expect(collectionEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');248 });249171250172 itEth('Can perform burnFromCross()', async ({helper}) => {251 itEth('Can perform burnFromCross()', async ({helper}) => {tests/src/eth/nonFungible.test.tsdiffbeforeafterboth175 // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);175 // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`);176 });176 });177 177 178 // TODO combine all minting tests in one place179 [180 'substrate' as const,181 'ethereum' as const,182 ].map(testCase => {178 itEth('Can perform mintCross()', async ({helper}) => {183 itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {179 const caller = await helper.eth.createAccountWithBalance(donor);184 const collectionAdmin = await helper.eth.createAccountWithBalance(donor);185186 const receiverEth = helper.eth.createAccount();187 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);188 const receiverSub = bob;180 const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);189 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);190191 // const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);181 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });192 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });182 const permissions: ITokenPropertyPermission[] = properties193 const permissions: ITokenPropertyPermission[] = properties183 .map(p => {194 .map(p => {184 return {195 return {185 key: p.key, permission: {196 key: p.key, permission: {186 tokenOwner: true,197 tokenOwner: false,187 collectionAdmin: true,198 collectionAdmin: true,188 mutable: true,199 mutable: false,189 },200 },190 };201 };191 });202 });195 tokenPrefix: 'ethp',206 tokenPrefix: 'ethp',196 tokenPropertyPermissions: permissions,207 tokenPropertyPermissions: permissions,197 });208 });198 await collection.addAdmin(minter, {Ethereum: caller});209 await collection.addAdmin(minter, {Ethereum: collectionAdmin});199 210 200 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);211 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);201 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true);212 const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', collectionAdmin, true);202 let expectedTokenId = await contract.methods.nextTokenId().call();213 let expectedTokenId = await contract.methods.nextTokenId().call();203 let result = await contract.methods.mintCross(receiverCross, []).send();214 let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();204 let tokenId = result.events.Transfer.returnValues.tokenId;215 let tokenId = result.events.Transfer.returnValues.tokenId;205 expect(tokenId).to.be.equal(expectedTokenId);216 expect(tokenId).to.be.equal(expectedTokenId);206217207 let event = result.events.Transfer;218 let event = result.events.Transfer;208 expect(event.address).to.be.equal(collectionAddress);219 expect(event.address).to.be.equal(collectionAddress);209 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');220 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');210 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));221 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));211 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);222 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);212 223 213 expectedTokenId = await contract.methods.nextTokenId().call();224 expectedTokenId = await contract.methods.nextTokenId().call();214 result = await contract.methods.mintCross(receiverCross, properties).send();225 result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();215 event = result.events.Transfer;226 event = result.events.Transfer;216 expect(event.address).to.be.equal(collectionAddress);227 expect(event.address).to.be.equal(collectionAddress);217 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');228 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');218 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));229 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));219 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);230 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);220 231 221 tokenId = result.events.Transfer.returnValues.tokenId;232 tokenId = result.events.Transfer.returnValues.tokenId;225 expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties236 expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties226 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));237 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));238 239 expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))240 .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});227 });241 });228 242 });243244 itEth('Non-owner and non admin cannot mintCross', async ({helper}) => {245 const nonOwner = await helper.eth.createAccountWithBalance(donor);246 const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);247248 const collection = await helper.nft.mintCollection(minter);249 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);250 const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft');251252 await expect(collectionEvm.methods.mintCross(nonOwnerCross, []).call({from: nonOwner}))253 .to.be.rejectedWith('PublicMintingNotAllowed');254 });255 229 //TODO: CORE-302 add eth methods256 //TODO: CORE-302 add eth methods230 itEth.skip('Can perform mintBulk()', async ({helper}) => {257 itEth.skip('Can perform mintBulk()', async ({helper}) => {376 });403 });377 }404 }405406 expect(await helper.nft.doesTokenExist(collection.collectionId, token.tokenId)).to.be.false;378 });407 });379 408 380 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {409 itEth('Can perform transfer with ApprovalForAll', async ({helper}) => {455 expect(await token2.doesExist()).to.be.false;484 expect(await token2.doesExist()).to.be.false;456 });485 });457486487 // TODO combine all approve tests in one place458 itEth('Can perform approveCross()', async ({helper}) => {488 itEth('Can perform approveCross()', async ({helper}) => {459 // arrange: create accounts489 // arrange: create accounts460 const owner = await helper.eth.createAccountWithBalance(donor, 100n);490 const owner = await helper.eth.createAccountWithBalance(donor, 100n);503 expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});533 expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});504 });534 });535536 itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {537 const nonOwner = await helper.eth.createAccountWithBalance(donor);538 const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);539 const owner = await helper.eth.createAccountWithBalance(donor);540 const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});541 const collectionEvm = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');542 const token = await collection.mintToken(minter, {Ethereum: owner});543544 await expect(collectionEvm.methods.approveCross(nonOwnerCross, token.tokenId).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');545 });505546506 itEth('Can reaffirm approved address', async ({helper}) => {547 itEth('Can reaffirm approved address', async ({helper}) => {507 const owner = await helper.eth.createAccountWithBalance(donor, 100n);548 const owner = await helper.eth.createAccountWithBalance(donor, 100n);tests/src/eth/reFungible.test.tsdiffbeforeafterboth137 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');137 expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI');138 });138 });139 139 140 [141 'substrate' as const,142 'ethereum' as const,143 ].map(testCase => {140 itEth('Can perform mintCross()', async ({helper}) => {144 itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => {141 const caller = await helper.eth.createAccountWithBalance(donor);145 const collectionAdmin = await helper.eth.createAccountWithBalance(donor);146147 const receiverEth = helper.eth.createAccount();148 const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);149 const receiverSub = bob;142 const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob);150 const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);151143 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });152 const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; });144 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true,153 const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {154 tokenOwner: false,145 collectionAdmin: true,155 collectionAdmin: true,146 mutable: true}}; });156 mutable: false}};147 157 });148 158 159 149 const collection = await helper.rft.mintCollection(minter, {160 const collection = await helper.rft.mintCollection(minter, {150 tokenPrefix: 'ethp',161 tokenPrefix: 'ethp',151 tokenPropertyPermissions: permissions,162 tokenPropertyPermissions: permissions,152 });163 });153 await collection.addAdmin(minter, {Ethereum: caller});164 await collection.addAdmin(minter, {Ethereum: collectionAdmin});154 165 155 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);166 const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);156 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller, true);167 const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', collectionAdmin, true);157 let expectedTokenId = await contract.methods.nextTokenId().call();168 let expectedTokenId = await contract.methods.nextTokenId().call();158 let result = await contract.methods.mintCross(receiverCross, []).send();169 let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send();159 let tokenId = result.events.Transfer.returnValues.tokenId;170 let tokenId = result.events.Transfer.returnValues.tokenId;160 expect(tokenId).to.be.equal(expectedTokenId);171 expect(tokenId).to.be.equal(expectedTokenId);161172162 let event = result.events.Transfer;173 let event = result.events.Transfer;163 expect(event.address).to.be.equal(collectionAddress);174 expect(event.address).to.be.equal(collectionAddress);164 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');175 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');165 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));176 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));166 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);177 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);167 178 168 expectedTokenId = await contract.methods.nextTokenId().call();179 expectedTokenId = await contract.methods.nextTokenId().call();169 result = await contract.methods.mintCross(receiverCross, properties).send();180 result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send();170 event = result.events.Transfer;181 event = result.events.Transfer;171 expect(event.address).to.be.equal(collectionAddress);182 expect(event.address).to.be.equal(collectionAddress);172 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');183 expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000');173 expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address));184 expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address));174 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);185 expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]);175 186 176 tokenId = result.events.Transfer.returnValues.tokenId;187 tokenId = result.events.Transfer.returnValues.tokenId;180 expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties191 expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties181 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));192 .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));193194 expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId))195 .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address});182 });196 });197 });183198184 itEth.skip('Can perform mintBulk()', async ({helper}) => {199 itEth.skip('Can perform mintBulk()', async ({helper}) => {185 const owner = await helper.eth.createAccountWithBalance(donor);200 const owner = await helper.eth.createAccountWithBalance(donor);tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth208 }208 }209 });209 });210 210211 itEth('Non-owner and non admin cannot approveCross', async ({helper}) => {212 const nonOwner = await helper.eth.createAccountWithBalance(donor);213 const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner);214 const owner = await helper.eth.createAccountWithBalance(donor);215 const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'});216 const token = await collection.mintToken(alice, 100n, {Ethereum: owner});217218 const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId);219 const tokenEvm = helper.ethNativeContract.rftToken(tokenAddress, owner);220221 await expect(tokenEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned');222 });223211 [224 [212 'transferFrom',225 'transferFrom',tests/src/eth/tokenProperties.test.tsdiffbeforeafterboth37 {mode: 'nft' as const, requiredPallets: []},37 {mode: 'nft' as const, requiredPallets: []},38 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},38 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},39 ].map(testCase =>39 ].map(testCase =>40 itEth.ifWithPallets(`[${testCase.mode}] Set and get token property permissions`, testCase.requiredPallets, async({helper}) => {40 itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => {41 const owner = await helper.eth.createAccountWithBalance(donor);41 const owner = await helper.eth.createAccountWithBalance(donor);42 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);42 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);43 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {43 for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) {72 {mode: 'nft' as const, requiredPallets: []},72 {mode: 'nft' as const, requiredPallets: []},73 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},73 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},74 ].map(testCase =>74 ].map(testCase =>75 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {75 itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => {76 const owner = await helper.eth.createAccountWithBalance(donor);76 const owner = await helper.eth.createAccountWithBalance(donor);77 77 78 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');78 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');79 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);79 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);808081 await collection.methods.setTokenPropertyPermissions([81 await collection.methods.setTokenPropertyPermissions([82 ['testKey_0', [82 ['testKey_0', [135 {mode: 'nft' as const, requiredPallets: []},134 {mode: 'nft' as const, requiredPallets: []},136 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},135 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},137 ].map(testCase =>136 ].map(testCase =>138 itEth.ifWithPallets(`[${testCase.mode}] Set and get multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {137 itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => {139 const owner = await helper.eth.createAccountWithBalance(donor);138 const owner = await helper.eth.createAccountWithBalance(donor);140 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);139 const caller = await helper.ethCrossAccount.createAccountWithBalance(donor);141 140 142 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');141 const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');143 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);142 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);144 await collection.methods.addCollectionAdminCross(caller).send({from: owner});143 await collection.methods.addCollectionAdminCross(caller).send({from: owner});145144146 await collection.methods.setTokenPropertyPermissions([145 await collection.methods.setTokenPropertyPermissions([452 {mode: 'nft' as const, requiredPallets: []},451 {mode: 'nft' as const, requiredPallets: []},453 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},452 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},454 ].map(testCase =>453 ].map(testCase =>455 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {454 itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => {456 const owner = await helper.eth.createAccountWithBalance(donor);455 const owner = await helper.eth.createAccountWithBalance(donor);457 const caller = await helper.eth.createAccountWithBalance(donor);456 const caller = await helper.eth.createAccountWithBalance(donor);458 457 459 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');458 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');460 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);459 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);461 460 462 await expect(collection.methods.setTokenPropertyPermissions([461 await expect(collection.methods.setTokenPropertyPermissions([463 ['testKey_0', [462 ['testKey_0', [472 {mode: 'nft' as const, requiredPallets: []},471 {mode: 'nft' as const, requiredPallets: []},473 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},472 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},474 ].map(testCase =>473 ].map(testCase =>475 itEth.ifWithPallets(`[${testCase.mode}] Cant set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {474 itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => {476 const owner = await helper.eth.createAccountWithBalance(donor);475 const owner = await helper.eth.createAccountWithBalance(donor);477 476 478 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');477 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');479 const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);478 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);480 479 481 await expect(collection.methods.setTokenPropertyPermissions([480 await expect(collection.methods.setTokenPropertyPermissions([482 // "Space" is invalid character481 // "Space" is invalid character488 ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); 487 ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); 489 }));488 }));490 489490 [491 {mode: 'nft' as const, requiredPallets: []},492 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},493 ].map(testCase =>494 itEth.ifWithPallets(`[${testCase.mode}] Can reconfigure token property permissions to stricter ones`, testCase.requiredPallets, async({helper}) => {495 const owner = await helper.eth.createAccountWithBalance(donor);496 497 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');498 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);499 500 // 1. Owner sets strict property-permissions:501 await collection.methods.setTokenPropertyPermissions([502 ['testKey', [503 [EthTokenPermissions.Mutable, true], 504 [EthTokenPermissions.TokenOwner, true], 505 [EthTokenPermissions.CollectionAdmin, true]],506 ],507 ]).send({from: owner});508 509 // 2. Owner can set stricter property-permissions:510 for(const values of [[true, true, false], [true, false, false], [false, false, false]]) {511 await collection.methods.setTokenPropertyPermissions([512 ['testKey', [513 [EthTokenPermissions.Mutable, values[0]], 514 [EthTokenPermissions.TokenOwner, values[1]], 515 [EthTokenPermissions.CollectionAdmin, values[2]]],516 ],517 ]).send({from: owner});518 }519520 expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{521 key: 'testKey',522 permission: {mutable: false, collectionAdmin: false, tokenOwner: false},523 }]);524 }));525526 [527 {mode: 'nft' as const, requiredPallets: []},528 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},529 ].map(testCase =>530 itEth.ifWithPallets(`[${testCase.mode}] Cannot reconfigure token property permissions to less strict ones`, testCase.requiredPallets, async({helper}) => {531 const owner = await helper.eth.createAccountWithBalance(donor);532 533 const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');534 const collection = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);535 536 // 1. Owner sets strict property-permissions:537 await collection.methods.setTokenPropertyPermissions([538 ['testKey', [539 [EthTokenPermissions.Mutable, false], 540 [EthTokenPermissions.TokenOwner, false], 541 [EthTokenPermissions.CollectionAdmin, false]],542 ],543 ]).send({from: owner});544545 // 2. Owner cannot set less strict property-permissions:546 for(const values of [[true, false, false], [false, true, false], [false, false, true]]) {547 await expect(collection.methods.setTokenPropertyPermissions([548 ['testKey', [549 [EthTokenPermissions.Mutable, values[0]], 550 [EthTokenPermissions.TokenOwner, values[1]], 551 [EthTokenPermissions.CollectionAdmin, values[2]]],552 ],553 ]).call({from: owner})).to.be.rejectedWith('NoPermission');554 }555 }));491});556});492557493558tests/src/util/index.tsdiffbeforeafterboth6import {IKeyringPair} from '@polkadot/types/types/interfaces';6import {IKeyringPair} from '@polkadot/types/types/interfaces';7import chai from 'chai';7import chai from 'chai';8import chaiAsPromised from 'chai-as-promised';8import chaiAsPromised from 'chai-as-promised';9import chaiSubset from 'chai-subset';9import {Context} from 'mocha';10import {Context} from 'mocha';10import config from '../config';11import config from '../config';11import {ChainHelperBase} from './playgrounds/unique';12import {ChainHelperBase} from './playgrounds/unique';12import {ILogger} from './playgrounds/types';13import {ILogger} from './playgrounds/types';13import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper} from './playgrounds/unique.dev';14import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper} from './playgrounds/unique.dev';141515chai.use(chaiAsPromised);16chai.use(chaiAsPromised);17chai.use(chaiSubset);16export const expect = chai.expect;18export const expect = chai.expect;171918const getTestHash = (filename: string) => {20const getTestHash = (filename: string) => {tests/src/vesting.test.tsdiffbeforeafterboth32 // arrange32 // arrange33 const [sender, recepient] = await helper.arrange.createAccounts([1000n, 1n], donor);33 const [sender, recepient] = await helper.arrange.createAccounts([1000n, 1n], donor);34 const currentRelayBlock = await helper.chain.getRelayBlockNumber();34 const currentRelayBlock = await helper.chain.getRelayBlockNumber();35 const SCHEDULE_1_PERIOD = 4n; // 6 blocks one period36 const SCHEDULE_1_START = currentRelayBlock + 6n; // Block when 1 schedule starts37 const SCHEDULE_2_PERIOD = 8n; // 12 blocks one period38 const SCHEDULE_2_START = currentRelayBlock + 12n; // Block when 2 schedule starts35 const schedule1 = {start: currentRelayBlock + 4n, period: 4n, periodCount: 2n, perPeriod: 50n * nominal};39 const schedule1 = {start: SCHEDULE_1_START, period: SCHEDULE_1_PERIOD, periodCount: 2n, perPeriod: 50n * nominal};36 const schedule2 = {start: currentRelayBlock + 8n, period: 8n, periodCount: 2n, perPeriod: 100n * nominal};40 const schedule2 = {start: SCHEDULE_2_START, period: SCHEDULE_2_PERIOD, periodCount: 2n, perPeriod: 100n * nominal};374138 // act42 // act39 await helper.balance.vestedTransfer(sender, recepient.address, schedule1);43 await helper.balance.vestedTransfer(sender, recepient.address, schedule1);59 expect(schedule[0]).to.deep.eq(schedule1);63 expect(schedule[0]).to.deep.eq(schedule1);60 expect(schedule[1]).to.deep.eq(schedule2);64 expect(schedule[1]).to.deep.eq(schedule2);616566 // Wait first part available:62 await helper.wait.forRelayBlockNumber(currentRelayBlock + 8n);67 await helper.wait.forRelayBlockNumber(SCHEDULE_1_START + SCHEDULE_1_PERIOD);63 await helper.balance.claim(recepient);68 await helper.balance.claim(recepient);646965 // check recepient balance after claim (50 tokens claimed):70 // check recepient balance after claim (50 tokens claimed, 250 left):66 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);71 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);67 expect(balanceRecepient.free / nominal).to.eq(300n);72 expect(balanceRecepient.free / nominal).to.eq(300n);68 expect(balanceRecepient.feeFrozen).to.eq(250n * nominal);73 expect(balanceRecepient.feeFrozen).to.eq(250n * nominal);69 expect(balanceRecepient.miscFrozen).to.eq(250n * nominal);74 expect(balanceRecepient.miscFrozen).to.eq(250n * nominal);70 expect(balanceRecepient.reserved).to.eq(0n);75 expect(balanceRecepient.reserved).to.eq(0n);71 76 77 // Wait first schedule ends and first part od second schedule:72 await helper.wait.forRelayBlockNumber(currentRelayBlock + 16n);78 await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD);73 await helper.balance.claim(recepient);79 await helper.balance.claim(recepient);748075 // check recepient balance after second claim (150 tokens claimed):81 // check recepient balance after second claim (150 tokens claimed, 100 left):76 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);82 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);77 expect(balanceRecepient.free / nominal).to.eq(300n);83 expect(balanceRecepient.free / nominal).to.eq(300n);78 expect(balanceRecepient.feeFrozen).to.eq(100n * nominal);84 expect(balanceRecepient.feeFrozen).to.eq(100n * nominal);84 expect(schedule).to.has.length(1);90 expect(schedule).to.has.length(1);85 expect(schedule[0]).to.deep.eq(schedule2);91 expect(schedule[0]).to.deep.eq(schedule2);869293 // Wait 2 schedule ends:87 await helper.wait.forRelayBlockNumber(currentRelayBlock + 24n);94 await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD * 2n);88 await helper.balance.claim(recepient);95 await helper.balance.claim(recepient);899690 // check recepient balance after second claim (100 tokens claimed):97 // check recepient balance after second claim (100 tokens claimed, 0 left):91 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);98 balanceRecepient = await helper.balance.getSubstrateFull(recepient.address);92 expect(balanceRecepient.free / nominal).to.eq(300n);99 expect(balanceRecepient.free / nominal).to.eq(300n);93 expect(balanceRecepient.feeFrozen).to.eq(0n);100 expect(balanceRecepient.feeFrozen).to.eq(0n);tests/yarn.lockdiffbeforeafterboth979 dependencies:979 dependencies:980 "@types/chai" "*"980 "@types/chai" "*"981981982"@types/chai-subset@^1.3.3":983 version "1.3.3"984 resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"985 integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==986 dependencies:987 "@types/chai" "*"988982"@types/chai@*", "@types/chai@^4.3.3":989"@types/chai@*", "@types/chai@^4.3.3":983 version "4.3.4"990 version "4.3.4"984 resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4"991 resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4"1568 version "1.1.1"1575 version "1.1.1"1569 resolved "https://registry.yarnpkg.com/chai-like/-/chai-like-1.1.1.tgz#8c558a414c34514e814d497c772547ceb7958f64"1576 resolved "https://registry.yarnpkg.com/chai-like/-/chai-like-1.1.1.tgz#8c558a414c34514e814d497c772547ceb7958f64"1570 integrity sha512-VKa9z/SnhXhkT1zIjtPACFWSoWsqVoaz1Vg+ecrKo5DCKVlgL30F/pEyEvXPBOVwCgLZcWUleCM/C1okaKdTTA==1577 integrity sha512-VKa9z/SnhXhkT1zIjtPACFWSoWsqVoaz1Vg+ecrKo5DCKVlgL30F/pEyEvXPBOVwCgLZcWUleCM/C1okaKdTTA==15781579chai-subset@^1.6.0:1580 version "1.6.0"1581 resolved "https://registry.yarnpkg.com/chai-subset/-/chai-subset-1.6.0.tgz#a5d0ca14e329a79596ed70058b6646bd6988cfe9"1582 integrity sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==157115831572chai@^4.3.6:1584chai@^4.3.6:1573 version "4.3.7"1585 version "4.3.7"