difftreelog
Merge pull request #565 from UniqueNetwork/tests/eth-playgrounds
in: master
15 files changed
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -30,6 +30,7 @@
"testEth": "mocha --timeout 9999999 -r ts-node/register './**/eth/**/*.test.ts'",
"testEthMarketplace": "mocha --timeout 9999999 -r ts-node/register './**/eth/marketplace/**/*.test.ts'",
"testEthNesting": "mocha --timeout 9999999 -r ts-node/register './**/eth/nesting/**/*.test.ts'",
+ "testEthPayable": "mocha --timeout 9999999 -r ts-node/register './**/eth/payable.test.ts'",
"load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",
"loadTransfer": "ts-node src/transfer.nload.ts",
"testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",
@@ -79,7 +80,8 @@
"testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
"testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
"testLimits": "mocha --timeout 9999999 -r ts-node/register ./**/limits.test.ts",
- "testEthCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createCollection.test.ts",
+ "testEthCreateNFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createNFTCollection.test.ts",
+ "testEthCreateRFTCollection": "mocha --timeout 9999999 -r ts-node/register ./**/eth/createRFTCollection.test.ts",
"testRFT": "mocha --timeout 9999999 -r ts-node/register ./**/refungible.test.ts",
"testFT": "mocha --timeout 9999999 -r ts-node/register ./**/fungible.test.ts",
"testRPC": "mocha --timeout 9999999 -r ts-node/register ./**/rpc.test.ts",
tests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -15,7 +15,7 @@
import {expect} from 'chai';
import privateKey from '../substrate/privateKey';
-import { UNIQUE } from '../util/helpers';
+import {UNIQUE} from '../util/helpers';
import {
createEthAccount,
createEthAccountWithBalance,
@@ -24,7 +24,6 @@
getCollectionAddressFromResult,
itWeb3,
recordEthFee,
- subToEth,
} from './util/helpers';
describe('Add collection admins', () => {
@@ -37,7 +36,7 @@
.send();
const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- const newAdmin = await createEthAccount(web3);
+ const newAdmin = createEthAccount(web3);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
const adminList = await api.rpc.unique.adminlist(collectionId);
@@ -92,7 +91,7 @@
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(admin).send();
- const user = await createEthAccount(web3);
+ const user = createEthAccount(web3);
await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: admin}))
.to.be.rejectedWith('NoPermission');
@@ -114,7 +113,7 @@
const notAdmin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
- const user = await createEthAccount(web3);
+ const user = createEthAccount(web3);
await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin}))
.to.be.rejectedWith('NoPermission');
@@ -175,7 +174,7 @@
.send();
const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
- const newAdmin = await createEthAccount(web3);
+ const newAdmin = createEthAccount(web3);
const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
{
@@ -226,7 +225,7 @@
const admin0 = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
await collectionEvm.methods.addCollectionAdmin(admin0).send();
- const admin1 = await createEthAccount(web3);
+ const admin1 = createEthAccount(web3);
await collectionEvm.methods.addCollectionAdmin(admin1).send();
await expect(collectionEvm.methods.removeCollectionAdmin(admin1).call({from: admin0}))
@@ -253,7 +252,7 @@
const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
await collectionEvm.methods.addCollectionAdmin(admin).send();
- const notAdmin = await createEthAccount(web3);
+ const notAdmin = createEthAccount(web3);
await expect(collectionEvm.methods.removeCollectionAdmin(admin).call({from: notAdmin}))
.to.be.rejectedWith('NoPermission');
tests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth1import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub, subToEth} from './util/helpers';3import nonFungibleAbi from './nonFungibleAbi.json';4import {expect} from 'chai';5import {evmToAddress} from '@polkadot/util-crypto';6import {submitTransactionAsync} from '../substrate/substrate-api';7import getBalance from '../substrate/get-balance';89describe('evm collection sponsoring', () => {10 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {11 const alice = privateKeyWrapper('//Alice');1213 const collection = await createCollectionExpectSuccess();14 await setCollectionSponsorExpectSuccess(collection, alice.address);15 await confirmSponsorshipExpectSuccess(collection);1617 const minter = createEthAccount(web3);18 expect(await web3.eth.getBalance(minter)).to.equal('0');1920 const address = collectionIdToAddress(collection);21 const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});2223 await enablePublicMintingExpectSuccess(alice, collection);24 await addToAllowListExpectSuccess(alice, collection, {Ethereum: minter});2526 const nextTokenId = await contract.methods.nextTokenId().call();27 expect(nextTokenId).to.equal('1');28 const result = await contract.methods.mint(minter, nextTokenId).send();29 const events = normalizeEvents(result.events);30 expect(events).to.be.deep.equal([31 {32 address,33 event: 'Transfer',34 args: {35 from: '0x0000000000000000000000000000000000000000',36 to: minter,37 tokenId: nextTokenId,38 },39 },40 ]);41 });4243 itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => {44 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);45 const collectionHelpers = evmCollectionHelpers(web3, owner);46 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();47 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);48 const sponsor = privateKeyWrapper('//Alice');49 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);5051 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;52 result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});53 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;54 55 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);56 await submitTransactionAsync(sponsor, confirmTx);57 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;58 59 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});60 expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);61 });6263 itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => {64 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const collectionHelpers = evmCollectionHelpers(web3, owner);66 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();67 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);68 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);69 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);7071 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;72 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});73 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;74 75 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});76 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;77 78 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});79 80 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});81 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');82 });8384 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {85 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);86 const collectionHelpers = evmCollectionHelpers(web3, owner);87 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();88 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);89 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);90 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);91 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});92 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;93 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;94 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;95 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));96 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');9798 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});99 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;100 expect(collectionSub.sponsorship.isConfirmed).to.be.true;101 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));102103 const user = createEthAccount(web3);104 const nextTokenId = await collectionEvm.methods.nextTokenId().call();105 expect(nextTokenId).to.be.equal('1');106107 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();108 expect(oldPermissions.mintMode).to.be.false;109 expect(oldPermissions.access).to.be.equal('Normal');110111 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});112 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});113 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});114115 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();116 expect(newPermissions.mintMode).to.be.true;117 expect(newPermissions.access).to.be.equal('AllowList');118119 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);120 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);121122 {123 const nextTokenId = await collectionEvm.methods.nextTokenId().call();124 expect(nextTokenId).to.be.equal('1');125 const result = await collectionEvm.methods.mintWithTokenURI(126 user,127 nextTokenId,128 'Test URI',129 ).send({from: user});130 const events = normalizeEvents(result.events);131132 expect(events).to.be.deep.equal([133 {134 address: collectionIdAddress,135 event: 'Transfer',136 args: {137 from: '0x0000000000000000000000000000000000000000',138 to: user,139 tokenId: nextTokenId,140 },141 },142 ]);143144 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);145 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);146147 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');148 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);149 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;150 }151 });152153 itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {154 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);155 const collectionHelpers = evmCollectionHelpers(web3, owner);156 const result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();157 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);158 const sponsor = privateKeyWrapper('//Alice');159 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);160161 await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});162 163 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);164 await submitTransactionAsync(sponsor, confirmTx);165 166 const user = createEthAccount(web3);167 const nextTokenId = await collectionEvm.methods.nextTokenId().call();168 expect(nextTokenId).to.be.equal('1');169170 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});171 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});172 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});173174 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);175 const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];176177 {178 const nextTokenId = await collectionEvm.methods.nextTokenId().call();179 expect(nextTokenId).to.be.equal('1');180 const result = await collectionEvm.methods.mintWithTokenURI(181 user,182 nextTokenId,183 'Test URI',184 ).send({from: user});185 const events = normalizeEvents(result.events);186187 expect(events).to.be.deep.equal([188 {189 address: collectionIdAddress,190 event: 'Transfer',191 args: {192 from: '0x0000000000000000000000000000000000000000',193 to: user,194 tokenId: nextTokenId,195 },196 },197 ]);198199 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);200 const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];201202 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');203 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);204 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;205 }206 });207208 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {209 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const collectionHelpers = evmCollectionHelpers(web3, owner);211 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();212 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);213 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);214 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);215 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();216 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;217 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;218 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;219 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));220 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');221 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);222 await sponsorCollection.methods.confirmCollectionSponsorship().send();223 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;224 expect(collectionSub.sponsorship.isConfirmed).to.be.true;225 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));226227 const user = createEthAccount(web3);228 await collectionEvm.methods.addCollectionAdmin(user).send();229 230 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);231 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);232 233 234 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);235 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();236 expect(nextTokenId).to.be.equal('1');237 result = await userCollectionEvm.methods.mintWithTokenURI(238 user,239 nextTokenId,240 'Test URI',241 ).send();242243 const events = normalizeEvents(result.events);244 const address = collectionIdToAddress(collectionId);245246 expect(events).to.be.deep.equal([247 {248 address,249 event: 'Transfer',250 args: {251 from: '0x0000000000000000000000000000000000000000',252 to: user,253 tokenId: nextTokenId,254 },255 },256 ]);257 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');258 259 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);260 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;263 });264});1import {addToAllowListExpectSuccess, bigIntToSub, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess} from '../util/helpers';2import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers';3import nonFungibleAbi from './nonFungibleAbi.json';4import {expect} from 'chai';5import {evmToAddress} from '@polkadot/util-crypto';6import {submitTransactionAsync} from '../substrate/substrate-api';7import getBalance from '../substrate/get-balance';89describe('evm collection sponsoring', () => {10 itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => {11 const alice = privateKeyWrapper('//Alice');1213 const collection = await createCollectionExpectSuccess();14 await setCollectionSponsorExpectSuccess(collection, alice.address);15 await confirmSponsorshipExpectSuccess(collection);1617 const minter = createEthAccount(web3);18 expect(await web3.eth.getBalance(minter)).to.equal('0');1920 const address = collectionIdToAddress(collection);21 const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS});2223 await enablePublicMintingExpectSuccess(alice, collection);24 await addToAllowListExpectSuccess(alice, collection, {Ethereum: minter});2526 const nextTokenId = await contract.methods.nextTokenId().call();27 expect(nextTokenId).to.equal('1');28 const result = await contract.methods.mint(minter, nextTokenId).send();29 const events = normalizeEvents(result.events);30 expect(events).to.be.deep.equal([31 {32 address,33 event: 'Transfer',34 args: {35 from: '0x0000000000000000000000000000000000000000',36 to: minter,37 tokenId: nextTokenId,38 },39 },40 ]);41 });4243 itWeb3('Set substrate sponsor', async ({api, web3, privateKeyWrapper}) => {44 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);45 const collectionHelpers = evmCollectionHelpers(web3, owner);46 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();47 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);48 const sponsor = privateKeyWrapper('//Alice');49 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);5051 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;52 result = await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});53 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;54 55 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);56 await submitTransactionAsync(sponsor, confirmTx);57 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;58 59 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});60 expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address);61 });6263 itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => {64 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);65 const collectionHelpers = evmCollectionHelpers(web3, owner);66 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();67 const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);68 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);69 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);7071 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;72 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});73 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true;74 75 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});76 expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false;77 78 await collectionEvm.methods.removeCollectionSponsor().send({from: owner});79 80 const sponsorTuple = await collectionEvm.methods.getCollectionSponsor().call({from: owner});81 expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000');82 });8384 itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => {85 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);86 const collectionHelpers = evmCollectionHelpers(web3, owner);87 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();88 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);89 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);90 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);91 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner});92 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;93 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;94 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;95 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));96 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');9798 await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});99 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;100 expect(collectionSub.sponsorship.isConfirmed).to.be.true;101 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));102103 const user = createEthAccount(web3);104 const nextTokenId = await collectionEvm.methods.nextTokenId().call();105 expect(nextTokenId).to.be.equal('1');106107 const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();108 expect(oldPermissions.mintMode).to.be.false;109 expect(oldPermissions.access).to.be.equal('Normal');110111 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});112 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});113 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});114115 const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();116 expect(newPermissions.mintMode).to.be.true;117 expect(newPermissions.access).to.be.equal('AllowList');118119 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);120 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);121122 {123 const nextTokenId = await collectionEvm.methods.nextTokenId().call();124 expect(nextTokenId).to.be.equal('1');125 const result = await collectionEvm.methods.mintWithTokenURI(126 user,127 nextTokenId,128 'Test URI',129 ).send({from: user});130 const events = normalizeEvents(result.events);131132 expect(events).to.be.deep.equal([133 {134 address: collectionIdAddress,135 event: 'Transfer',136 args: {137 from: '0x0000000000000000000000000000000000000000',138 to: user,139 tokenId: nextTokenId,140 },141 },142 ]);143144 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);145 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);146147 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');148 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);149 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;150 }151 });152153 itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => {154 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);155 const collectionHelpers = evmCollectionHelpers(web3, owner);156 const result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();157 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);158 const sponsor = privateKeyWrapper('//Alice');159 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);160161 await collectionEvm.methods.setCollectionSponsorSubstrate(sponsor.addressRaw).send({from: owner});162 163 const confirmTx = await api.tx.unique.confirmSponsorship(collectionId);164 await submitTransactionAsync(sponsor, confirmTx);165 166 const user = createEthAccount(web3);167 const nextTokenId = await collectionEvm.methods.nextTokenId().call();168 expect(nextTokenId).to.be.equal('1');169170 await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});171 await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});172 await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});173174 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);175 const sponsorBalanceBefore = (await getBalance(api, [sponsor.address]))[0];176177 {178 const nextTokenId = await collectionEvm.methods.nextTokenId().call();179 expect(nextTokenId).to.be.equal('1');180 const result = await collectionEvm.methods.mintWithTokenURI(181 user,182 nextTokenId,183 'Test URI',184 ).send({from: user});185 const events = normalizeEvents(result.events);186187 expect(events).to.be.deep.equal([188 {189 address: collectionIdAddress,190 event: 'Transfer',191 args: {192 from: '0x0000000000000000000000000000000000000000',193 to: user,194 tokenId: nextTokenId,195 },196 },197 ]);198199 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);200 const sponsorBalanceAfter = (await getBalance(api, [sponsor.address]))[0];201202 expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');203 expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter);204 expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true;205 }206 });207208 itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => {209 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);210 const collectionHelpers = evmCollectionHelpers(web3, owner);211 let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();212 const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);213 const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper);214 const collectionEvm = evmCollection(web3, owner, collectionIdAddress);215 result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();216 let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;217 const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format;218 expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;219 expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));220 await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor');221 const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);222 await sponsorCollection.methods.confirmCollectionSponsorship().send();223 collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;224 expect(collectionSub.sponsorship.isConfirmed).to.be.true;225 expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format)));226227 const user = createEthAccount(web3);228 await collectionEvm.methods.addCollectionAdmin(user).send();229 230 const ownerBalanceBefore = await ethBalanceViaSub(api, owner);231 const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);232 233 234 const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);235 const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();236 expect(nextTokenId).to.be.equal('1');237 result = await userCollectionEvm.methods.mintWithTokenURI(238 user,239 nextTokenId,240 'Test URI',241 ).send();242243 const events = normalizeEvents(result.events);244 const address = collectionIdToAddress(collectionId);245246 expect(events).to.be.deep.equal([247 {248 address,249 event: 'Transfer',250 args: {251 from: '0x0000000000000000000000000000000000000000',252 to: user,253 tokenId: nextTokenId,254 },255 },256 ]);257 expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');258 259 const ownerBalanceAfter = await ethBalanceViaSub(api, owner);260 expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);261 const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);262 expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;263 });264});tests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth--- a/tests/src/eth/createNFTCollection.test.ts
+++ b/tests/src/eth/createNFTCollection.test.ts
@@ -181,7 +181,7 @@
});
itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
- const owner = await createEthAccount(web3);
+ const owner = createEthAccount(web3);
const helper = evmCollectionHelpers(web3, owner);
const collectionName = 'A';
const description = 'A';
@@ -194,7 +194,7 @@
itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const notOwner = await createEthAccount(web3);
+ const notOwner = createEthAccount(web3);
const collectionHelpers = evmCollectionHelpers(web3, owner);
const result = await collectionHelpers.methods.createNonfungibleCollection('A', 'A', 'A').send();
const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
tests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -189,7 +189,7 @@
});
itWeb3('(!negative test!) Create collection (no funds)', async ({web3}) => {
- const owner = await createEthAccount(web3);
+ const owner = createEthAccount(web3);
const helper = evmCollectionHelpers(web3, owner);
const collectionName = 'A';
const description = 'A';
@@ -202,7 +202,7 @@
itWeb3('(!negative test!) Check owner', async ({api, web3, privateKeyWrapper}) => {
const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const notOwner = await createEthAccount(web3);
+ const notOwner = createEthAccount(web3);
const collectionHelpers = evmCollectionHelpers(web3, owner);
const result = await collectionHelpers.methods.createRefungibleCollection('A', 'A', 'A').send();
const {collectionIdAddress} = await getCollectionAddressFromResult(api, result);
tests/src/eth/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/eth/nesting/nest.test.ts
+++ b/tests/src/eth/nesting/nest.test.ts
@@ -1,217 +1,220 @@
-import {ApiPromise} from '@polkadot/api';
+import {IKeyringPair} from '@polkadot/types/types';
import {Contract} from 'web3-eth-contract';
-import {expect} from 'chai';
-import Web3 from 'web3';
-import {createEthAccountWithBalance, evmCollectionHelpers, GAS_ARGS, getCollectionAddressFromResult, itWeb3, tokenIdToAddress} from '../../eth/util/helpers';
-import nonFungibleAbi from '../nonFungibleAbi.json';
+import {itEth, EthUniqueHelper, usingEthPlaygrounds, expect} from '../util/playgrounds';
+
const createNestingCollection = async (
- api: ApiPromise,
- web3: Web3,
+ helper: EthUniqueHelper,
owner: string,
): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => {
- const collectionHelper = evmCollectionHelpers(web3, owner);
-
- const result = await collectionHelper.methods
- .createNonfungibleCollection('A', 'B', 'C')
- .send();
- const {collectionIdAddress: collectionAddress, collectionId} = await getCollectionAddressFromResult(api, result);
+ const {collectionAddress, collectionId} = await helper.eth.createNonfungibleCollection(owner, 'A', 'B', 'C');
- const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionAddress, {from: owner, ...GAS_ARGS});
+ const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
await contract.methods.setCollectionNesting(true).send({from: owner});
return {collectionId, collectionAddress, contract};
};
-describe('Integration Test: EVM Nesting', () => {
- itWeb3('NFT: allows an Owner to nest/unnest their token', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
- // Create a token to be nested
- const targetNFTTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetNFTTokenId,
- ).send({from: owner});
-
- const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId);
-
- // Create a nested token
- const firstTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- targetNftTokenAddress,
- firstTokenId,
- ).send({from: owner});
+describe('EVM nesting tests group', () => {
+ let donor: IKeyringPair;
- expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Create a token to be nested and nest
- const secondTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- secondTokenId,
- ).send({from: owner});
-
- await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
-
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
-
- // Unnest token back
- await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
- expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = privateKey('//Alice');
+ });
});
- itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
- await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-
- // Create a token to nest into
- const targetNftTokenId = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- targetNftTokenId,
- ).send({from: owner});
- const nftTokenAddressA1 = tokenIdToAddress(collectionIdA, targetNftTokenId);
-
- // Create a token for nesting in the same collection as the target
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
-
- // Create a token for nesting in a different collection
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- owner,
- nftTokenIdB,
- ).send({from: owner});
-
- // Nest
- await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
- expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
-
- await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
- expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
- });
-});
-
-describe('Negative Test: EVM Nesting', async() => {
- itWeb3('NFT: disallows to nest token if nesting is disabled', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
- await contract.methods.setCollectionNesting(false).send({from: owner});
-
- // Create a token to nest into
- const targetNftTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetNftTokenId,
- ).send({from: owner});
-
- const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNftTokenId);
-
- // Create a token to nest
- const nftTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- nftTokenId,
- ).send({from: owner});
-
- // Try to nest
- await expect(contract.methods
- .transfer(targetNftTokenAddress, nftTokenId)
- .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId, contract} = await createNestingCollection(api, web3, owner);
-
- // Mint a token
- const targetTokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- owner,
- targetTokenId,
- ).send({from: owner});
- const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId);
-
- // Mint a token belonging to a different account
- const tokenId = await contract.methods.nextTokenId().call();
- await contract.methods.mint(
- malignant,
- tokenId,
- ).send({from: owner});
-
- // Try to nest one token in another as a non-owner account
- await expect(contract.methods
- .transfer(targetTokenAddress, tokenId)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
- });
-
- itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(api, web3, owner);
-
- await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
-
- // Create a token in one collection
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
- const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection belonging to someone else
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- malignant,
- nftTokenIdB,
- ).send({from: owner});
-
- // Try to drag someone else's token into the other collection and nest
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ describe('Integration Test: EVM Nesting', () => {
+ itEth('NFT: allows an Owner to nest/unnest their token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Create a token to be nested
+ const targetNFTTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetNFTTokenId,
+ ).send({from: owner});
+
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNFTTokenId);
+
+ // Create a nested token
+ const firstTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ targetNftTokenAddress,
+ firstTokenId,
+ ).send({from: owner});
+
+ expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Create a token to be nested and nest
+ const secondTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ secondTokenId,
+ ).send({from: owner});
+
+ await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner});
+
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress);
+
+ // Unnest token back
+ await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner});
+ expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner);
+ });
+
+ itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+ // Create a token to nest into
+ const targetNftTokenId = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ targetNftTokenId,
+ ).send({from: owner});
+ const nftTokenAddressA1 = helper.ethAddress.fromTokenId(collectionIdA, targetNftTokenId);
+
+ // Create a token for nesting in the same collection as the target
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+
+ // Create a token for nesting in a different collection
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ owner,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Nest
+ await contractA.methods.transfer(nftTokenAddressA1, nftTokenIdA).send({from: owner});
+ expect(await contractA.methods.ownerOf(nftTokenIdA).call()).to.be.equal(nftTokenAddressA1);
+
+ await contractB.methods.transfer(nftTokenAddressA1, nftTokenIdB).send({from: owner});
+ expect(await contractB.methods.ownerOf(nftTokenIdB).call()).to.be.equal(nftTokenAddressA1);
+ });
});
- itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => {
- const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
-
- const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(api, web3, owner);
- const {contract: contractB} = await createNestingCollection(api, web3, owner);
-
- await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
-
- // Create a token in one collection
- const nftTokenIdA = await contractA.methods.nextTokenId().call();
- await contractA.methods.mint(
- owner,
- nftTokenIdA,
- ).send({from: owner});
- const nftTokenAddressA = tokenIdToAddress(collectionIdA, nftTokenIdA);
-
- // Create a token in another collection
- const nftTokenIdB = await contractB.methods.nextTokenId().call();
- await contractB.methods.mint(
- owner,
- nftTokenIdB,
- ).send({from: owner});
-
- // Try to nest into a token in the other collection, disallowed in the first
- await expect(contractB.methods
- .transfer(nftTokenAddressA, nftTokenIdB)
- .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+ describe('Negative Test: EVM Nesting', async() => {
+ itEth('NFT: disallows to nest token if nesting is disabled', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+ await contract.methods.setCollectionNesting(false).send({from: owner});
+
+ // Create a token to nest into
+ const targetNftTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetNftTokenId,
+ ).send({from: owner});
+
+ const targetNftTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetNftTokenId);
+
+ // Create a token to nest
+ const nftTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ nftTokenId,
+ ).send({from: owner});
+
+ // Try to nest
+ await expect(contract.methods
+ .transfer(targetNftTokenAddress, nftTokenId)
+ .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId, contract} = await createNestingCollection(helper, owner);
+
+ // Mint a token
+ const targetTokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ owner,
+ targetTokenId,
+ ).send({from: owner});
+ const targetTokenAddress = helper.ethAddress.fromTokenId(collectionId, targetTokenId);
+
+ // Mint a token belonging to a different account
+ const tokenId = await contract.methods.nextTokenId().call();
+ await contract.methods.mint(
+ malignant,
+ tokenId,
+ ).send({from: owner});
+
+ // Try to nest one token in another as a non-owner account
+ await expect(contract.methods
+ .transfer(targetTokenAddress, tokenId)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+ const malignant = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {collectionAddress: collectionAddressB, contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA, collectionAddressB]).send({from: owner});
+
+ // Create a token in one collection
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection belonging to someone else
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ malignant,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Try to drag someone else's token into the other collection and nest
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest');
+ });
+
+ itEth('NFT: disallows to nest token in an unlisted collection', async ({helper}) => {
+ const owner = await helper.eth.createAccountWithBalance(donor);
+
+ const {collectionId: collectionIdA, collectionAddress: collectionAddressA, contract: contractA} = await createNestingCollection(helper, owner);
+ const {contract: contractB} = await createNestingCollection(helper, owner);
+
+ await contractA.methods.setCollectionNesting(true, [collectionAddressA]).send({from: owner});
+
+ // Create a token in one collection
+ const nftTokenIdA = await contractA.methods.nextTokenId().call();
+ await contractA.methods.mint(
+ owner,
+ nftTokenIdA,
+ ).send({from: owner});
+ const nftTokenAddressA = helper.ethAddress.fromTokenId(collectionIdA, nftTokenIdA);
+
+ // Create a token in another collection
+ const nftTokenIdB = await contractB.methods.nextTokenId().call();
+ await contractB.methods.mint(
+ owner,
+ nftTokenIdB,
+ ).send({from: owner});
+
+ // Try to nest into a token in the other collection, disallowed in the first
+ await expect(contractB.methods
+ .transfer(nftTokenAddressA, nftTokenIdB)
+ .call()).to.be.rejectedWith('SourceCollectionIsNotAllowedToNest');
+ });
});
});
tests/src/eth/payable.test.tsdiffbeforeafterboth--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -14,97 +14,91 @@
// You should have received a copy of the GNU General Public License
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-import {expect} from 'chai';
-import {submitTransactionAsync} from '../substrate/substrate-api';
-import {createEthAccountWithBalance, deployCollector, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
-import {evmToAddress} from '@polkadot/util-crypto';
-import {getGenericResult, UNIQUE} from '../util/helpers';
-import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance';
+import {IKeyringPair} from '@polkadot/types/types';
+
+import {itEth, expect, usingEthPlaygrounds} from './util/playgrounds';
describe('EVM payable contracts', () => {
- itWeb3('Evm contract can receive wei from eth account', async ({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
+ let donor: IKeyringPair;
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', ...GAS_ARGS});
+ before(async function() {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ donor = privateKey('//Alice');
+ });
+ });
+
+ itEth('Evm contract can receive wei from eth account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+
+ const web3 = helper.getWeb3();
+
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: '10000', gas: helper.eth.DEFAULT_GAS});
expect(await contract.methods.getCollected().call()).to.be.equal('10000');
});
- itWeb3('Evm contract can receive wei from substrate account', async ({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ itEth('Evm contract can receive wei from substrate account', async ({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+
+ const weiCount = '10000';
// Transaction fee/value will be payed from subToEth(sender) evm balance,
// which is backed by evmToAddress(subToEth(sender)) substrate balance
- await transferBalanceToEth(api, alice, subToEth(alice.address));
+ await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address), 5n);
+
- {
- const tx = api.tx.evm.call(
- subToEth(alice.address),
- contract.options.address,
- contract.methods.giveMoney().encodeABI(),
- '10000',
- GAS_ARGS.gas,
- await web3.eth.getGasPrice(),
- null,
- null,
- [],
- );
- const events = await submitTransactionAsync(alice, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
- }
+ await helper.eth.callEVM(alice, contract.options.address, contract.methods.giveMoney().encodeABI(), weiCount);
- expect(await contract.methods.getCollected().call()).to.be.equal('10000');
+ expect(await contract.methods.getCollected().call()).to.be.equal(weiCount);
});
// We can't handle sending balance to backing storage of evm balance, because evmToAddress operation is irreversible
- itWeb3('Wei sent directly to backing storage of evm contract balance is unaccounted', async({api, web3, privateKeyWrapper}) => {
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ itEth('Wei sent directly to backing storage of evm contract balance is unaccounted', async({helper}) => {
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([10n], donor);
+
+ const weiCount = 10_000n;
- await transferBalanceExpectSuccess(api, alice, evmToAddress(contract.options.address), '10000');
+ await helper.eth.transferBalanceFromSubstrate(alice, contract.options.address, weiCount, false);
- expect(await contract.methods.getUnaccounted().call()).to.be.equal('10000');
+ expect(await contract.methods.getUnaccounted().call()).to.be.equal(weiCount.toString());
});
- itWeb3('Balance can be retrieved from evm contract', async({api, web3, privateKeyWrapper}) => {
- const FEE_BALANCE = 1000n * UNIQUE;
- const CONTRACT_BALANCE = 1n * UNIQUE;
+ itEth('Balance can be retrieved from evm contract', async({helper, privateKey}) => {
+ const FEE_BALANCE = 10n * helper.balance.getOneTokenNominal();
+ const CONTRACT_BALANCE = 1n * helper.balance.getOneTokenNominal();
+
+ const deployer = await helper.eth.createAccountWithBalance(donor);
+ const contract = await helper.eth.deployCollectorContract(deployer);
+ const [alice] = await helper.arrange.createAccounts([20n], donor);
- const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
- const contract = await deployCollector(web3, deployer);
- const alice = privateKeyWrapper('//Alice');
+ const web3 = helper.getWeb3();
- await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), ...GAS_ARGS});
+ await web3.eth.sendTransaction({from: deployer, to: contract.options.address, value: CONTRACT_BALANCE.toString(), gas: helper.eth.DEFAULT_GAS});
- const receiver = privateKeyWrapper(`//Receiver${Date.now()}`);
+ const receiver = privateKey(`//Receiver${Date.now()}`);
// First receive balance on eth balance of bob
{
- const ethReceiver = subToEth(receiver.address);
+ const ethReceiver = helper.address.substrateToEth(receiver.address);
expect(await web3.eth.getBalance(ethReceiver)).to.be.equal('0');
await contract.methods.withdraw(ethReceiver).send({from: deployer});
expect(await web3.eth.getBalance(ethReceiver)).to.be.equal(CONTRACT_BALANCE.toString());
}
// Some balance is required to pay fee for evm.withdraw call
- await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
+ await helper.balance.transferToSubstrate(alice, receiver.address, FEE_BALANCE);
+ // await transferBalanceExpectSuccess(api, alice, receiver.address, FEE_BALANCE.toString());
// Withdraw balance from eth to substrate
{
- const initialReceiverBalance = await getBalanceSingle(api, receiver.address);
- const tx = api.tx.evm.withdraw(
- subToEth(receiver.address),
- CONTRACT_BALANCE.toString(),
- );
- const events = await submitTransactionAsync(receiver, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
- const finalReceiverBalance = await getBalanceSingle(api, receiver.address);
+ const initialReceiverBalance = await helper.balance.getSubstrate(receiver.address);
+ await helper.executeExtrinsic(receiver, 'api.tx.evm.withdraw', [helper.address.substrateToEth(receiver.address), CONTRACT_BALANCE.toString()], true);
+ const finalReceiverBalance = await helper.balance.getSubstrate(receiver.address);
expect(finalReceiverBalance > initialReceiverBalance).to.be.true;
}
tests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -15,7 +15,7 @@
// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
import {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE, requirePallets, Pallets} from '../util/helpers';
-import {collectionIdFromAddress, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createNonfungibleCollection, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueNFT, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, createRefungibleCollection, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth, uniqueRefungible, uniqueRefungibleToken} from './util/helpers';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
tests/src/eth/util/playgrounds/index.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/index.ts
@@ -0,0 +1,49 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import {IKeyringPair} from '@polkadot/types/types';
+
+import config from '../../../config';
+
+import {EthUniqueHelper} from './unique.dev';
+import {SilentLogger, SilentConsole} from '../../../util/playgrounds/unique.dev';
+
+export {EthUniqueHelper} from './unique.dev';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+chai.use(chaiAsPromised);
+export const expect = chai.expect;
+
+export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
+
+ const helper = new EthUniqueHelper(new SilentLogger());
+
+ try {
+ await helper.connect(config.substrateUrl);
+ await helper.connectWeb3(config.substrateUrl);
+ const ss58Format = helper.chain.getChainProperties().ss58Format;
+ const privateKey = (seed: string) => helper.util.fromSeed(seed, ss58Format);
+ await code(helper, privateKey);
+ }
+ finally {
+ await helper.disconnect();
+ await helper.disconnectWeb3();
+ silentConsole.disable();
+ }
+};
+
+export async function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {
+ let i: any = it;
+ if (opts.only) i = i.only;
+ else if (opts.skip) i = i.skip;
+ i(name, async () => {
+ await usingEthPlaygrounds(async (helper, privateKey) => {
+ await cb({helper, privateKey});
+ });
+ });
+}
+itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {only: true});
+itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string) => IKeyringPair }) => any) => itEth(name, cb, {skip: true});
\ No newline at end of file
tests/src/eth/util/playgrounds/types.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/types.ts
@@ -0,0 +1,9 @@
+export interface ContractImports {
+ solPath: string;
+ fsPath: string;
+}
+
+export interface CompiledContract {
+ abi: any;
+ object: string;
+}
\ No newline at end of file
tests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -0,0 +1,268 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+/* eslint-disable function-call-argument-newline */
+
+import {readFile} from 'fs/promises';
+
+import Web3 from 'web3';
+import {WebsocketProvider} from 'web3-core';
+import {Contract} from 'web3-eth-contract';
+
+import * as solc from 'solc';
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import {IKeyringPair} from '@polkadot/types/types';
+
+import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev';
+
+import {ContractImports, CompiledContract} from './types';
+
+// Native contracts ABI
+import collectionHelpersAbi from '../../collectionHelpersAbi.json';
+import fungibleAbi from '../../fungibleAbi.json';
+import nonFungibleAbi from '../../nonFungibleAbi.json';
+import refungibleAbi from '../../reFungibleAbi.json';
+import refungibleTokenAbi from '../../reFungibleTokenAbi.json';
+import contractHelpersAbi from './../contractHelpersAbi.json';
+
+class EthGroupBase {
+ helper: EthUniqueHelper;
+
+ constructor(helper: EthUniqueHelper) {
+ this.helper = helper;
+ }
+}
+
+
+class ContractGroup extends EthGroupBase {
+ async findImports(imports?: ContractImports[]){
+ if(!imports) return function(path: string) {
+ return {error: `File not found: ${path}`};
+ };
+
+ const knownImports = {} as any;
+ for(const imp of imports) {
+ knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
+ }
+
+ return function(path: string) {
+ if(knownImports.hasOwnPropertyDescriptor(path)) return {contents: knownImports[path]};
+ return {error: `File not found: ${path}`};
+ };
+ }
+
+ async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
+ const out = JSON.parse(solc.compile(JSON.stringify({
+ language: 'Solidity',
+ sources: {
+ [`${name}.sol`]: {
+ content: src,
+ },
+ },
+ settings: {
+ outputSelection: {
+ '*': {
+ '*': ['*'],
+ },
+ },
+ },
+ }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name];
+
+ return {
+ abi: out.abi,
+ object: '0x' + out.evm.bytecode.object,
+ };
+ }
+
+ async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[]): Promise<Contract> {
+ const compiledContract = await this.compile(name, src, imports);
+ return this.deployByAbi(signer, compiledContract.abi, compiledContract.object);
+ }
+
+ async deployByAbi(signer: string, abi: any, object: string): Promise<Contract> {
+ const web3 = this.helper.getWeb3();
+ const contract = new web3.eth.Contract(abi, undefined, {
+ data: object,
+ from: signer,
+ gas: this.helper.eth.DEFAULT_GAS,
+ });
+ return await contract.deploy({data: object}).send({from: signer});
+ }
+
+}
+
+class NativeContractGroup extends EthGroupBase {
+
+ contractHelpers(caller: string): Contract {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+ }
+
+ collectionHelpers(caller: string) {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+ }
+
+ collection(address: string, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract {
+ const abi = {
+ 'nft': nonFungibleAbi,
+ 'rft': refungibleAbi,
+ 'ft': fungibleAbi,
+ }[mode];
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
+ }
+
+ rftTokenByAddress(address: string, caller?: string): Contract {
+ const web3 = this.helper.getWeb3();
+ return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})});
+ }
+
+ rftToken(collectionId: number, tokenId: number, caller?: string): Contract {
+ return this.rftTokenByAddress(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller);
+ }
+}
+
+
+class EthGroup extends EthGroupBase {
+ DEFAULT_GAS = 2_500_000;
+
+ createAccount() {
+ const web3 = this.helper.getWeb3();
+ const account = web3.eth.accounts.create();
+ web3.eth.accounts.wallet.add(account.privateKey);
+ return account.address;
+ }
+
+ async createAccountWithBalance(donor: IKeyringPair, amount=1000n) {
+ const account = this.createAccount();
+ await this.transferBalanceFromSubstrate(donor, account, amount);
+
+ return account;
+ }
+
+ async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount=1000n, inTokens=true) {
+ return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
+ }
+
+ async callEVM(signer: IKeyringPair, contractAddress: string, abi: any, value: string, gasLimit?: number) {
+ if(!gasLimit) gasLimit = this.DEFAULT_GAS;
+ const web3 = this.helper.getWeb3();
+ const gasPrice = await web3.eth.getGasPrice();
+ // TODO: check execution status
+ await this.helper.executeExtrinsic(
+ signer,
+ 'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
+ true,
+ );
+ }
+
+ async createNonfungibleCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> {
+ const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
+
+ const result = await collectionHelper.methods.createNonfungibleCollection(name, description, tokenPrefix).send();
+
+ const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+ const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+
+ return {collectionId, collectionAddress};
+ }
+
+ async deployCollectorContract(signer: string): Promise<Contract> {
+ return await this.helper.ethContract.deployByCode(signer, 'Collector', `
+ // SPDX-License-Identifier: UNLICENSED
+ pragma solidity ^0.8.6;
+
+ contract Collector {
+ uint256 collected;
+ fallback() external payable {
+ giveMoney();
+ }
+ function giveMoney() public payable {
+ collected += msg.value;
+ }
+ function getCollected() public view returns (uint256) {
+ return collected;
+ }
+ function getUnaccounted() public view returns (uint256) {
+ return address(this).balance - collected;
+ }
+
+ function withdraw(address payable target) public {
+ target.transfer(collected);
+ collected = 0;
+ }
+ }
+ `);
+ }
+}
+
+
+class EthAddressGroup extends EthGroupBase {
+ extractCollectionId(address: string): number {
+ if (!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
+ return parseInt(address.substr(address.length - 8), 16);
+ }
+
+ fromCollectionId(collectionId: number): string {
+ if (collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
+ return Web3.utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
+ }
+
+ extractTokenId(address: string): {collectionId: number, tokenId: number} {
+ if (!address.startsWith('0x'))
+ throw 'address not starts with "0x"';
+ if (address.length > 42)
+ throw 'address length is more than 20 bytes';
+ return {
+ collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
+ tokenId: Number('0x' + address.substring(address.length - 8)),
+ };
+ }
+
+ fromTokenId(collectionId: number, tokenId: number): string {
+ return this.helper.util.getNestingTokenAddress(collectionId, tokenId);
+ }
+
+ normalizeAddress(address: string): string {
+ return '0x' + address.substring(address.length - 40);
+ }
+}
+
+
+export class EthUniqueHelper extends DevUniqueHelper {
+ web3: Web3 | null = null;
+ web3Provider: WebsocketProvider | null = null;
+
+ eth: EthGroup;
+ ethAddress: EthAddressGroup;
+ ethNativeContract: NativeContractGroup;
+ ethContract: ContractGroup;
+
+ constructor(logger: { log: (msg: any, level: any) => void, level: any }) {
+ super(logger);
+ this.eth = new EthGroup(this);
+ this.ethAddress = new EthAddressGroup(this);
+ this.ethNativeContract = new NativeContractGroup(this);
+ this.ethContract = new ContractGroup(this);
+ }
+
+ getWeb3(): Web3 {
+ if(this.web3 === null) throw Error('Web3 not connected');
+ return this.web3;
+ }
+
+ async connectWeb3(wsEndpoint: string) {
+ if(this.web3 !== null) return;
+ this.web3Provider = new Web3.providers.WebsocketProvider(wsEndpoint);
+ this.web3 = new Web3(this.web3Provider);
+ }
+
+ async disconnectWeb3() {
+ if(this.web3 === null) return;
+ this.web3Provider?.connection.close();
+ this.web3 = null;
+ }
+}
+
\ No newline at end of file
tests/src/substrate/substrate-api.tsdiffbeforeafterboth--- a/tests/src/substrate/substrate-api.ts
+++ b/tests/src/substrate/substrate-api.ts
@@ -25,6 +25,8 @@
import privateKey from './privateKey';
import promisifySubstrate from './promisify-substrate';
+import {SilentConsole} from '../util/playgrounds/unique.dev';
+
function defaultApiOptions(): ApiOptions {
@@ -74,26 +76,9 @@
settings = settings || defaultApiOptions();
const api: ApiPromise = new ApiPromise(settings);
let result: T = null as unknown as T;
-
- // TODO: Remove, this is temporary: Filter unneeded API output
- // (Jaco promised it will be removed in the next version)
- const consoleErr = console.error;
- const consoleLog = console.log;
- const consoleWarn = console.warn;
- const outFn = (printer: any) => (...args: any[]) => {
- for (const arg of args) {
- if (typeof arg !== 'string')
- continue;
- if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
- return;
- }
- printer(...args);
- };
-
- console.error = outFn(consoleErr.bind(console));
- console.log = outFn(consoleLog.bind(console));
- console.warn = outFn(consoleWarn.bind(console));
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
try {
await promisifySubstrate(api, async () => {
@@ -106,9 +91,7 @@
})();
} finally {
await api.disconnect();
- console.error = consoleErr;
- console.log = consoleLog;
- console.warn = consoleWarn;
+ silentConsole.disable();
}
return result as T;
}
tests/src/util/playgrounds/index.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/index.ts
+++ b/tests/src/util/playgrounds/index.ts
@@ -4,37 +4,13 @@
import {IKeyringPair} from '@polkadot/types/types';
import config from '../../config';
import '../../interfaces/augment-api-events';
-import {DevUniqueHelper} from './unique.dev';
+import {DevUniqueHelper, SilentLogger, SilentConsole} from './unique.dev';
-class SilentLogger {
- log(msg: any, level: any): void { }
- level = {
- ERROR: 'ERROR' as const,
- WARNING: 'WARNING' as const,
- INFO: 'INFO' as const,
- };
-}
export const usingPlaygrounds = async (code: (helper: DevUniqueHelper, privateKey: (seed: string) => IKeyringPair) => Promise<void>) => {
- // TODO: Remove, this is temporary: Filter unneeded API output
- // (Jaco promised it will be removed in the next version)
- const consoleErr = console.error;
- const consoleLog = console.log;
- const consoleWarn = console.warn;
+ const silentConsole = new SilentConsole();
+ silentConsole.enable();
- const outFn = (printer: any) => (...args: any[]) => {
- for (const arg of args) {
- if (typeof arg !== 'string')
- continue;
- if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
- return;
- }
- printer(...args);
- };
-
- console.error = outFn(consoleErr.bind(console));
- console.log = outFn(consoleLog.bind(console));
- console.warn = outFn(consoleWarn.bind(console));
const helper = new DevUniqueHelper(new SilentLogger());
try {
@@ -45,8 +21,6 @@
}
finally {
await helper.disconnect();
- console.error = consoleErr;
- console.log = consoleLog;
- console.warn = consoleWarn;
+ silentConsole.disable();
}
};
tests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -5,10 +5,56 @@
import {UniqueHelper} from './unique';
import {ApiPromise, WsProvider} from '@polkadot/api';
import * as defs from '../../interfaces/definitions';
-import {TSigner} from './types';
import {IKeyringPair} from '@polkadot/types/types';
+export class SilentLogger {
+ log(_msg: any, _level: any): void { }
+ level = {
+ ERROR: 'ERROR' as const,
+ WARNING: 'WARNING' as const,
+ INFO: 'INFO' as const,
+ };
+}
+
+
+export class SilentConsole {
+ // TODO: Remove, this is temporary: Filter unneeded API output
+ // (Jaco promised it will be removed in the next version)
+ consoleErr: any;
+ consoleLog: any;
+ consoleWarn: any;
+
+ constructor() {
+ this.consoleErr = console.error;
+ this.consoleLog = console.log;
+ this.consoleWarn = console.warn;
+ }
+
+ enable() {
+ const outFn = (printer: any) => (...args: any[]) => {
+ for (const arg of args) {
+ if (typeof arg !== 'string')
+ continue;
+ if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis: UniqueApi/2, RmrkApi/1') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
+ return;
+ }
+ printer(...args);
+ };
+
+ console.error = outFn(this.consoleErr.bind(console));
+ console.log = outFn(this.consoleLog.bind(console));
+ console.warn = outFn(this.consoleWarn.bind(console));
+ }
+
+ disable() {
+ console.error = this.consoleErr;
+ console.log = this.consoleLog;
+ console.warn = this.consoleWarn;
+ }
+}
+
+
export class DevUniqueHelper extends UniqueHelper {
/**
* Arrange methods for tests
@@ -20,7 +66,7 @@
this.arrange = new ArrangeGroup(this);
}
- async connect(wsEndpoint: string, listeners?: any): Promise<void> {
+ async connect(wsEndpoint: string, _listeners?: any): Promise<void> {
const wsProvider = new WsProvider(wsEndpoint);
this.api = new ApiPromise({
provider: wsProvider,
@@ -85,7 +131,7 @@
}
}
- await Promise.all(transactions).catch(e => {});
+ await Promise.all(transactions).catch(_e => {});
//#region TODO remove this region, when nonce problem will be solved
const checkBalances = async () => {
@@ -113,13 +159,14 @@
return accounts;
};
-
+
/**
* Wait for specified bnumber of blocks
* @param blocksCount number of blocks to wait
* @returns
*/
async waitNewBlocks(blocksCount = 1): Promise<void> {
+ // eslint-disable-next-line no-async-promise-executor
const promise = new Promise<void>(async (resolve) => {
const unsubscribe = await this.helper.api!.rpc.chain.subscribeNewHeads(() => {
if (blocksCount > 0) {
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -317,6 +317,7 @@
if(options !== null) return transaction.signAndSend(sender, options, callback);
return transaction.signAndSend(sender, callback);
};
+ // eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
const unsub = await sign((result: any) => {
@@ -388,6 +389,7 @@
type: this.chainLogType.EXTRINSIC,
status: result.status,
call: extrinsic,
+ signer: this.getSignerAddress(sender),
params,
} as IUniqueHelperLog;
@@ -1087,11 +1089,11 @@
return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));
}
- getCollectionObject(collectionId: number): any {
+ getCollectionObject(_collectionId: number): any {
return null;
}
- getTokenObject(collectionId: number, tokenId: number): any {
+ getTokenObject(_collectionId: number, _tokenId: number): any {
return null;
}
}