--- a/tests/src/eth/collectionSponsoring.test.ts +++ b/tests/src/eth/collectionSponsoring.test.ts @@ -1,33 +1,45 @@ -import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, enablePublicMintingExpectSuccess, getDetailedCollectionInfo, setCollectionSponsorExpectSuccess, UNIQUE} from '../util/helpers'; -import {itWeb3, createEthAccount, collectionIdToAddress, GAS_ARGS, normalizeEvents, createEthAccountWithBalance, evmCollectionHelpers, getCollectionAddressFromResult, evmCollection, ethBalanceViaSub} from './util/helpers'; -import nonFungibleAbi from './nonFungibleAbi.json'; -import {expect} from 'chai'; -import {evmToAddress} from '@polkadot/util-crypto'; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds} from './../util/playgrounds/index'; +import {itEth, expect} from '../eth/util/playgrounds'; describe('evm collection sponsoring', () => { - itWeb3('sponsors mint transactions', async ({web3, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); + let donor: IKeyringPair; + let alice: IKeyringPair; + let nominal: bigint; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + nominal = helper.balance.getOneTokenNominal(); + }); + }); + + beforeEach(async () => { + await usingPlaygrounds(async (helper) => { + [alice] = await helper.arrange.createAccounts([1000n], donor); + }); + }); - const collection = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collection, alice.address); - await confirmSponsorshipExpectSuccess(collection); + itEth('sponsors mint transactions', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}}); + await collection.setSponsor(alice, alice.address); + await collection.confirmSponsorship(alice); - const minter = createEthAccount(web3); - expect(await web3.eth.getBalance(minter)).to.equal('0'); + const minter = helper.eth.createAccount(); + expect(await helper.balance.getEthereum(minter)).to.equal(0n); - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collection), {from: minter, ...GAS_ARGS}); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', minter); - await enablePublicMintingExpectSuccess(alice, collection); - await addToAllowListExpectSuccess(alice, collection, {Ethereum: minter}); + await collection.addToAllowList(alice, {Ethereum: minter}); const nextTokenId = await contract.methods.nextTokenId().call(); expect(nextTokenId).to.equal('1'); const result = await contract.methods.mint(minter, nextTokenId).send(); - const events = normalizeEvents(result.events); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { - address, + address: collectionAddress, event: 'Transfer', args: { from: '0x0000000000000000000000000000000000000000', @@ -59,13 +71,14 @@ // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address); // }); - itWeb3('Remove sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionHelpers = evmCollectionHelpers(web3, owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)}); - const {collectionIdAddress} = await getCollectionAddressFromResult(api, result); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + itEth('Remove sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); + + let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); @@ -80,30 +93,31 @@ expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000'); }); - itWeb3('Sponsoring collection from evm address via access list', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionHelpers = evmCollectionHelpers(web3, owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)}); - const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + itEth('Sponsoring collection from evm address via access list', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); + + let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); + const collection = helper.nft.getCollectionObject(collectionId); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); + result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); - let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; - const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format; - expect(collectionSub.sponsorship.isUnconfirmed).to.be.true; - expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format))); + let collectionData = (await collection.getData())!; + expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); - collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; - expect(collectionSub.sponsorship.isConfirmed).to.be.true; - expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format))); + collectionData = (await collection.getData())!; + expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - const user = createEthAccount(web3); + const user = helper.eth.createAccount(); const nextTokenId = await collectionEvm.methods.nextTokenId().call(); expect(nextTokenId).to.be.equal('1'); - const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); + const oldPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); expect(oldPermissions.mintMode).to.be.false; expect(oldPermissions.access).to.be.equal('Normal'); @@ -111,12 +125,12 @@ await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner}); await collectionEvm.methods.setCollectionMintMode(true).send({from: owner}); - const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); + const newPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); expect(newPermissions.mintMode).to.be.true; expect(newPermissions.access).to.be.equal('AllowList'); - const ownerBalanceBefore = await ethBalanceViaSub(api, owner); - const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor); + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); { const nextTokenId = await collectionEvm.methods.nextTokenId().call(); @@ -126,7 +140,7 @@ nextTokenId, 'Test URI', ).send({from: user}); - const events = normalizeEvents(result.events); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { @@ -140,8 +154,8 @@ }, ]); - const ownerBalanceAfter = await ethBalanceViaSub(api, owner); - const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor); + const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter); @@ -205,33 +219,34 @@ // } // }); - itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionHelpers = evmCollectionHelpers(web3, owner); - let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * UNIQUE)}); - const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collectionEvm = evmCollection(web3, owner, collectionIdAddress); + itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); + + let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const collectionId = helper.ethAddress.extractCollectionId(collectionIdAddress); + const collection = helper.nft.getCollectionObject(collectionId); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); + result = await collectionEvm.methods.setCollectionSponsor(sponsor).send(); - let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; - const ss58Format = (api.registry.getChainProperties())!.toJSON().ss58Format; - expect(collectionSub.sponsorship.isUnconfirmed).to.be.true; - expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format))); + let collectionData = (await collection.getData())!; + expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); - const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress); + + const sponsorCollection = helper.ethNativeContract.collection(collectionIdAddress, 'nft', sponsor); await sponsorCollection.methods.confirmCollectionSponsorship().send(); - collectionSub = (await getDetailedCollectionInfo(api, collectionId))!; - expect(collectionSub.sponsorship.isConfirmed).to.be.true; - expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor, Number(ss58Format))); + collectionData = (await collection.getData())!; + expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - const user = createEthAccount(web3); + const user = helper.eth.createAccount(); await collectionEvm.methods.addCollectionAdmin(user).send(); - const ownerBalanceBefore = await ethBalanceViaSub(api, owner); - const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor); - - - const userCollectionEvm = evmCollection(web3, user, collectionIdAddress); + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + + const userCollectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', user); const nextTokenId = await userCollectionEvm.methods.nextTokenId().call(); expect(nextTokenId).to.be.equal('1'); result = await userCollectionEvm.methods.mintWithTokenURI( @@ -240,8 +255,8 @@ 'Test URI', ).send(); - const events = normalizeEvents(result.events); - const address = collectionIdToAddress(collectionId); + const events = helper.eth.normalizeEvents(result.events); + const address = helper.ethAddress.fromCollectionId(collectionId); expect(events).to.be.deep.equal([ { @@ -256,9 +271,9 @@ ]); expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - const ownerBalanceAfter = await ethBalanceViaSub(api, owner); + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); - const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; }); }); --- a/tests/src/eth/contractSponsoring.test.ts +++ b/tests/src/eth/contractSponsoring.test.ts @@ -14,45 +14,39 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . +import {IKeyringPair} from '@polkadot/types/types'; import * as solc from 'solc'; -import {expect} from 'chai'; -import {expectSubstrateEventsAtBlock} from '../util/helpers'; -import Web3 from 'web3'; +import {EthUniqueHelper} from './util/playgrounds/unique.dev'; +import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from '../eth/util/playgrounds'; +import {usingPlaygrounds} from '../util/playgrounds'; +import {CompiledContract} from './util/playgrounds/types'; -import { - contractHelpers, - createEthAccountWithBalance, - transferBalanceToEth, - deployFlipper, - itWeb3, - SponsoringMode, - createEthAccount, - ethBalanceViaSub, - normalizeEvents, - CompiledContract, - GAS_ARGS, - subToEth, -} from './util/helpers'; -import {submitTransactionAsync} from '../substrate/substrate-api'; +describe('Sponsoring EVM contracts', () => { + let donor: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (_helper, privateKey) => { + donor = privateKey('//Alice'); + }); + }); + + itEth('Self sponsored can be set by the address that deployed the contract', async ({helper, privateKey}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const flipper = await helper.eth.deployFlipper(owner); + const helpers = helper.ethNativeContract.contractHelpers(owner); -describe('Sponsoring EVM contracts', () => { - itWeb3('Self sponsored can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected; expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; }); - itWeb3('Set self sponsored events', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Set self sponsored events', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const flipper = await helper.eth.deployFlipper(owner); + const helpers = helper.ethNativeContract.contractHelpers(owner); const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); - // console.log(result); - const ethEvents = normalizeEvents(result.events); + const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events); expect(ethEvents).to.be.deep.equal([ { address: flipper.options.address, @@ -71,62 +65,59 @@ }, }, ]); - - await expectSubstrateEventsAtBlock( - api, - result.blockNumber, - 'evmContractHelpers', - ['ContractSponsorSet','ContractSponsorshipConfirmed'], - ); }); - itWeb3('Self sponsored can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Self sponsored can not be set by the address that did not deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const notOwner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission'); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; }); - itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsoring can be set by the address that has deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected; expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true; }); - itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const notOwner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission'); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; }); - itWeb3('Sponsor can be set by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true; }); - itWeb3('Set sponsor event', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Set sponsor event', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); - const events = normalizeEvents(result.events); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { address: flipper.options.address, @@ -137,45 +128,41 @@ }, }, ]); - - await expectSubstrateEventsAtBlock( - api, - result.blockNumber, - 'evmContractHelpers', - ['ContractSponsorSet'], - ); }); - itWeb3('Sponsor can not be set by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsor can not be set by the address that did not deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const notOwner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).call({from: notOwner})).to.be.rejectedWith('NoPermission'); expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false; }); - itWeb3('Sponsorship can be confirmed by the address that pending as sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected; expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; }); - itWeb3('Confirm sponsorship event', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Confirm sponsorship event', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - const events = normalizeEvents(result.events); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { address: flipper.options.address, @@ -186,41 +173,37 @@ }, }, ]); + }); - await expectSubstrateEventsAtBlock( - api, - result.blockNumber, - 'evmContractHelpers', - ['ContractSponsorshipConfirmed'], - ); - }); + itEth('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const notSponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); - itWeb3('Sponsorship can not be confirmed by the address that not pending as sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPermission'); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; }); - itWeb3('Sponsorship can not be confirmed by the address that not set as sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notSponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsorship can not be confirmed by the address that not set as sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const notSponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await expect(helpers.methods.confirmSponsorship(flipper.options.address).call({from: notSponsor})).to.be.rejectedWith('NoPendingSponsor'); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; }); - itWeb3('Get self sponsored sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Get self sponsored sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); const result = await helpers.methods.sponsor(flipper.options.address).call(); @@ -229,11 +212,12 @@ expect(result[1]).to.be.eq('0'); }); - itWeb3('Get confirmed sponsor', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Get confirmed sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); @@ -243,11 +227,11 @@ expect(result[1]).to.be.eq('0'); }); - itWeb3('Sponsor can be removed by the address that deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); @@ -258,17 +242,17 @@ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; }); - itWeb3('Remove sponsor event', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Remove sponsor event', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); const result = await helpers.methods.removeSponsor(flipper.options.address).send(); - const events = normalizeEvents(result.events); + const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { address: flipper.options.address, @@ -278,21 +262,14 @@ }, }, ]); - - await expectSubstrateEventsAtBlock( - api, - result.blockNumber, - 'evmContractHelpers', - ['ContractSponsorRemoved'], - ); }); - itWeb3('Sponsor can not be removed by the address that did not deployed the contract', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const notOwner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const notOwner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); @@ -303,14 +280,12 @@ expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; }); - itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const flipper = await deployFlipper(web3, owner); - - const helpers = contractHelpers(web3, owner); + itEth('In generous mode, non-allowlisted user transaction will be sponsored', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); @@ -318,57 +293,52 @@ await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor); - const callerBalanceBefore = await ethBalanceViaSub(api, caller); + const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); + const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; // Balance should be taken from sponsor instead of caller - const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor); - const callerBalanceAfter = await ethBalanceViaSub(api, caller); + const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); + const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; expect(callerBalanceAfter).to.be.eq(callerBalanceBefore); }); - - itWeb3('In generous mode, non-allowlisted user transaction will be self sponsored', async ({api, web3, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('In generous mode, non-allowlisted user transaction will be self sponsored', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - await transferBalanceToEth(api, alice, flipper.options.address); + await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address); - const contractBalanceBefore = await ethBalanceViaSub(api, flipper.options.address); - const callerBalanceBefore = await ethBalanceViaSub(api, caller); + const contractBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address)); + const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; // Balance should be taken from sponsor instead of caller - const contractBalanceAfter = await ethBalanceViaSub(api, flipper.options.address); - const callerBalanceAfter = await ethBalanceViaSub(api, caller); + const contractBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(flipper.options.address)); + const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); expect(contractBalanceAfter < contractBalanceBefore).to.be.true; expect(callerBalanceAfter).to.be.eq(callerBalanceBefore); }); - itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = createEthAccount(web3); - - const flipper = await deployFlipper(web3, owner); + itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = helper.eth.createAccount(); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); - const helpers = contractHelpers(web3, owner); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); @@ -378,51 +348,47 @@ await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor); + const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); expect(sponsorBalanceBefore).to.be.not.equal('0'); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; // Balance should be taken from flipper instead of caller - const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor); + const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; }); - itWeb3('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({api, web3, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = createEthAccount(web3); - - const flipper = await deployFlipper(web3, owner); + 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}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccount(); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); - const helpers = contractHelpers(web3, owner); - await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - await transferBalanceToEth(api, alice, flipper.options.address); + await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address); - const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address); + const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address); expect(originalFlipperBalance).to.be.not.equal('0'); await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/); expect(await flipper.methods.getValue().call()).to.be.false; // Balance should be taken from flipper instead of caller - const balanceAfter = await web3.eth.getBalance(flipper.options.address); - expect(+balanceAfter).to.be.equals(+originalFlipperBalance); + // FIXME the comment is wrong! What check should be here? + const balanceAfter = await helper.balance.getEthereum(flipper.options.address); + expect(balanceAfter).to.be.equals(originalFlipperBalance); }); - itWeb3('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - - const flipper = await deployFlipper(web3, owner); + itEth('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); - const helpers = contractHelpers(web3, owner); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); @@ -432,27 +398,26 @@ await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor); - const callerBalanceBefore = await ethBalanceViaSub(api, caller); + const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); + const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; - const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor); - const callerBalanceAfter = await ethBalanceViaSub(api, caller); + const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); + const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; expect(callerBalanceAfter).to.be.equals(callerBalanceBefore); }); - itWeb3('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const originalCallerBalance = await web3.eth.getBalance(caller); - - const flipper = await deployFlipper(web3, owner); - - const helpers = contractHelpers(web3, owner); + itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + + const originalCallerBalance = await helper.balance.getEthereum(caller); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); @@ -462,34 +427,36 @@ await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - const originalFlipperBalance = await web3.eth.getBalance(sponsor); + const originalFlipperBalance = await helper.balance.getEthereum(sponsor); expect(originalFlipperBalance).to.be.not.equal('0'); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; - expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance); + expect(await helper.balance.getEthereum(caller)).to.be.equals(originalCallerBalance); - const newFlipperBalance = await web3.eth.getBalance(sponsor); + const newFlipperBalance = await helper.balance.getEthereum(sponsor); expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance); await flipper.methods.flip().send({from: caller}); - expect(await web3.eth.getBalance(sponsor)).to.be.equal(newFlipperBalance); - expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance); + expect(await helper.balance.getEthereum(sponsor)).to.be.equal(newFlipperBalance); + expect(await helper.balance.getEthereum(caller)).to.be.not.equals(originalCallerBalance); }); // TODO: Find a way to calculate default rate limit - itWeb3('Default rate limit equals 7200', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Default rate limit equals 7200', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200'); }); }); describe('Sponsoring Fee Limit', () => { + let donor: IKeyringPair; + let alice: IKeyringPair; + let DEFAULT_GAS: number; - let testContract: CompiledContract; - function compileTestContract() { if (!testContract) { const input = { @@ -537,46 +504,67 @@ return testContract; } - async function deployTestContract(web3: Web3, owner: string) { + async function deployTestContract(helper: EthUniqueHelper, owner: string) { + const web3 = helper.getWeb3(); const compiled = compileTestContract(); const testContract = new web3.eth.Contract(compiled.abi, undefined, { data: compiled.object, from: owner, - ...GAS_ARGS, + gas: DEFAULT_GAS, }); return await testContract.deploy({data: compiled.object}).send({from: owner}); } - itWeb3('Default fee limit', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + before(async () => { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + DEFAULT_GAS = helper.eth.DEFAULT_GAS; + }); + }); + + beforeEach(async () => { + await usingPlaygrounds(async (helper) => { + [alice] = await helper.arrange.createAccounts([1000n], donor); + }); + }); + + let testContract: CompiledContract; + + + + itEth('Default fee limit', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('115792089237316195423570985008687907853269984665640564039457584007913129639935'); }); - itWeb3('Set fee limit', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Set fee limit', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send(); expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equals('100'); }); - itWeb3('Negative test - set fee limit by non-owner', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const stranger = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, owner); - const helpers = contractHelpers(web3, owner); + itEth('Negative test - set fee limit by non-owner', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const stranger = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected; }); - itWeb3('Negative test - check that eth transactions exceeding fee limit are not executed', async ({api, web3, privateKeyWrapper}) => { - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const user = await createEthAccountWithBalance(api, web3, privateKeyWrapper); + itEth('Negative test - check that eth transactions exceeding fee limit are not executed', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const user = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); - const testContract = await deployTestContract(web3, owner); - const helpers = contractHelpers(web3, owner); + const testContract = await deployTestContract(helper, owner); await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner}); @@ -584,24 +572,24 @@ await helpers.methods.setSponsor(testContract.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor}); - const gasPrice = BigInt(await web3.eth.getGasPrice()); + const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice()); await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send(); - const originalUserBalance = await web3.eth.getBalance(user); + const originalUserBalance = await helper.balance.getEthereum(user); await testContract.methods.test(100).send({from: user, gas: 2_000_000}); - expect(await web3.eth.getBalance(user)).to.be.equal(originalUserBalance); + expect(await helper.balance.getEthereum(user)).to.be.equal(originalUserBalance); await testContract.methods.test(100).send({from: user, gas: 2_100_000}); - expect(await web3.eth.getBalance(user)).to.not.be.equal(originalUserBalance); + expect(await helper.balance.getEthereum(user)).to.not.be.equal(originalUserBalance); }); - itWeb3('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({api, web3, privateKeyWrapper}) => { - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); + itEth('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({helper, privateKey}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const helpers = helper.ethNativeContract.contractHelpers(owner); - const testContract = await deployTestContract(web3, owner); - const helpers = contractHelpers(web3, owner); + const testContract = await deployTestContract(helper, owner); await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner}); @@ -609,43 +597,29 @@ await helpers.methods.setSponsor(testContract.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor}); - const gasPrice = BigInt(await web3.eth.getGasPrice()); + const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice()); await helpers.methods.setSponsoringFeeLimit(testContract.options.address, 2_000_000n * gasPrice).send(); - const alice = privateKeyWrapper('//Alice'); - const originalAliceBalance = (await api.query.system.account(alice.address)).data.free.toBigInt(); - - await submitTransactionAsync( + const originalAliceBalance = await helper.balance.getSubstrate(alice.address); + + await helper.eth.sendEVM( alice, - api.tx.evm.call( - subToEth(alice.address), - testContract.options.address, - testContract.methods.test(100).encodeABI(), - Uint8Array.from([]), - 2_000_000n, - gasPrice, - null, - null, - [], - ), + testContract.options.address, + testContract.methods.test(100).encodeABI(), + '0', + 2_000_000, ); - expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance); + // expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance); + expect(await helper.balance.getSubstrate(alice.address)).to.be.equal(originalAliceBalance); - await submitTransactionAsync( + await helper.eth.sendEVM( alice, - api.tx.evm.call( - subToEth(alice.address), - testContract.options.address, - testContract.methods.test(100).encodeABI(), - Uint8Array.from([]), - 2_100_000n, - gasPrice, - null, - null, - [], - ), + testContract.options.address, + testContract.methods.test(100).encodeABI(), + '0', + 2_100_000, ); - expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.not.be.equal(originalAliceBalance); + expect(await helper.balance.getSubstrate(alice.address)).to.not.be.equal(originalAliceBalance); }); }); --- a/tests/src/eth/scheduling.test.ts +++ b/tests/src/eth/scheduling.test.ts @@ -18,7 +18,8 @@ import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers'; import {scheduleExpectSuccess, waitNewBlocks, requirePallets, Pallets} from '../util/helpers'; -describe('Scheduing EVM smart contracts', () => { +// TODO mrshiposha update this test in #581 +describe.skip('Scheduing EVM smart contracts', () => { before(async function() { await requirePallets(this, [Pallets.Scheduler]); }); --- a/tests/src/eth/sponsoring.test.ts +++ b/tests/src/eth/sponsoring.test.ts @@ -14,20 +14,31 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {expect} from 'chai'; -import {contractHelpers, createEthAccount, createEthAccountWithBalance, deployCollector, deployFlipper, itWeb3, SponsoringMode} from './util/helpers'; +import {IKeyringPair} from '@polkadot/types/types'; +import {itEth, expect, SponsoringMode} from '../eth/util/playgrounds'; +import {usingPlaygrounds} from './../util/playgrounds/index'; describe('EVM sponsoring', () => { - itWeb3('Fee is deducted from contract if sponsoring is enabled', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = createEthAccount(web3); - const originalCallerBalance = await web3.eth.getBalance(caller); - expect(originalCallerBalance).to.be.equal('0'); + let donor: IKeyringPair; - const flipper = await deployFlipper(web3, owner); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + }); + }); + + itEth('Fee is deducted from contract if sponsoring is enabled', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = helper.eth.createAccount(); + const originalCallerBalance = await helper.balance.getEthereum(caller); + + expect(originalCallerBalance).to.be.equal(0n); + + const flipper = await helper.eth.deployFlipper(owner); + + const helpers = helper.ethNativeContract.contractHelpers(owner); - const helpers = contractHelpers(web3, owner); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); @@ -39,27 +50,29 @@ await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true; - const originalSponsorBalance = await web3.eth.getBalance(sponsor); - expect(originalSponsorBalance).to.be.not.equal('0'); + const originalSponsorBalance = await helper.balance.getEthereum(sponsor); + expect(originalSponsorBalance).to.be.not.equal(0n); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; // Balance should be taken from flipper instead of caller - expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance); - expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance); + expect(await helper.balance.getEthereum(caller)).to.be.equal(originalCallerBalance); + expect(await helper.balance.getEthereum(sponsor)).to.be.not.equal(originalSponsorBalance); }); - itWeb3('...but this doesn\'t applies to payable value', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const sponsor = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const originalCallerBalance = await web3.eth.getBalance(caller); - expect(originalCallerBalance).to.be.not.equal('0'); + itEth('...but this doesn\'t applies to payable value', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + const originalCallerBalance = await helper.balance.getEthereum(caller); + + expect(originalCallerBalance).to.be.not.equal(0n); + + const collector = await helper.eth.deployCollectorContract(owner); - const collector = await deployCollector(web3, owner); + const helpers = helper.ethNativeContract.contractHelpers(owner); - const helpers = contractHelpers(web3, owner); await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner}); @@ -71,14 +84,14 @@ await helpers.methods.setSponsor(collector.options.address, sponsor).send({from: owner}); await helpers.methods.confirmSponsorship(collector.options.address).send({from: sponsor}); - const originalSponsorBalance = await web3.eth.getBalance(sponsor); - expect(originalSponsorBalance).to.be.not.equal('0'); + const originalSponsorBalance = await helper.balance.getEthereum(sponsor); + expect(originalSponsorBalance).to.be.not.equal(0n); await collector.methods.giveMoney().send({from: caller, value: '10000'}); // Balance will be taken from both caller (value) and from collector (fee) - expect(await web3.eth.getBalance(caller)).to.be.equals((BigInt(originalCallerBalance) - 10000n).toString()); - expect(await web3.eth.getBalance(sponsor)).to.be.not.equals(originalSponsorBalance); + expect(await helper.balance.getEthereum(caller)).to.be.equals((originalCallerBalance - 10000n)); + expect(await helper.balance.getEthereum(sponsor)).to.be.not.equals(originalSponsorBalance); expect(await collector.methods.getCollected().call()).to.be.equal('10000'); }); }); --- a/tests/src/eth/tokenProperties.test.ts +++ b/tests/src/eth/tokenProperties.test.ts @@ -1,94 +1,119 @@ -import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess} from '../util/helpers'; -import {cartesian, collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3} from './util/helpers'; -import nonFungibleAbi from './nonFungibleAbi.json'; -import {expect} from 'chai'; -import {executeTransaction} from '../substrate/substrate-api'; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds} from './../util/playgrounds/index'; +import {itEth, expect} from '../eth/util/playgrounds'; describe('EVM token properties', () => { - itWeb3('Can be reconfigured', async({web3, api, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); + let donor: IKeyringPair; + let alice: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([1000n], donor); + }); + }); + + itEth('Can be reconfigured', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) { - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller}); - - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); - + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'ethp'}); + await collection.addAdmin(alice, {Ethereum: caller}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(address, 'nft', caller); + await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller}); - const state = (await api.query.common.collectionPropertyPermissions(collection)).toJSON(); - expect(state).to.be.deep.equal({ - [web3.utils.toHex('testKey')]: {mutable, collectionAdmin, tokenOwner}, - }); + const state = await collection.getPropertyPermissions(); + expect(state).to.be.deep.equal([{ + key: 'testKey', + permission: {mutable, collectionAdmin, tokenOwner}, + }]); } }); - itWeb3('Can be set', async({web3, api, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - const token = await createItemExpectSuccess(alice, collection, 'NFT'); - await executeTransaction(api, alice, api.tx.unique.setTokenPropertyPermissions(collection, [{ - key: 'testKey', - permission: { - collectionAdmin: true, - }, - }])); + itEth('Can be set', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: [{ + key: 'testKey', + permission: { + collectionAdmin: true, + }, + }], + }); + const token = await collection.mintToken(alice); - await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller}); + await collection.addAdmin(alice, {Ethereum: caller}); - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(address, 'nft', caller); - await contract.methods.setProperty(token, 'testKey', Buffer.from('testValue')).send({from: caller}); + await contract.methods.setProperty(token.tokenId, 'testKey', Buffer.from('testValue')).send({from: caller}); - const [{value}] = (await api.rpc.unique.tokenProperties(collection, token, ['testKey'])).toHuman()! as any; + const [{value}] = await token.getProperties(['testKey']); expect(value).to.equal('testValue'); }); - itWeb3('Can be deleted', async({web3, api, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - const token = await createItemExpectSuccess(alice, collection, 'NFT'); - await executeTransaction(api, alice, api.tx.unique.setTokenPropertyPermissions(collection, [{ - key: 'testKey', - permission: { - mutable: true, - collectionAdmin: true, - }, - }])); - await executeTransaction(api, alice, api.tx.unique.setTokenProperties(collection, token, [{key: 'testKey', value: 'testValue'}])); + itEth('Can be deleted', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: [{ + key: 'testKey', + permission: { + mutable: true, + collectionAdmin: true, + }, + }], + }); + + await collection.addAdmin(alice, {Ethereum: caller}); - await addCollectionAdminExpectSuccess(alice, collection, {Ethereum: caller}); + const token = await collection.mintToken(alice); + await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]); - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(address, 'nft', caller); - await contract.methods.deleteProperty(token, 'testKey').send({from: caller}); + await contract.methods.deleteProperty(token.tokenId, 'testKey').send({from: caller}); - const result = (await api.rpc.unique.tokenProperties(collection, token, ['testKey'])).toJSON()! as any; + const result = await token.getProperties(['testKey']); expect(result.length).to.equal(0); }); - itWeb3('Can be read', async({web3, api, privateKeyWrapper}) => { - const alice = privateKeyWrapper('//Alice'); - const caller = createEthAccount(web3); - const collection = await createCollectionExpectSuccess({mode: {type:'NFT'}}); - const token = await createItemExpectSuccess(alice, collection, 'NFT'); - await executeTransaction(api, alice, api.tx.unique.setTokenPropertyPermissions(collection, [{ - key: 'testKey', - permission: { - collectionAdmin: true, - }, - }])); - await executeTransaction(api, alice, api.tx.unique.setTokenProperties(collection, token, [{key: 'testKey', value: 'testValue'}])); + itEth('Can be read', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: [{ + key: 'testKey', + permission: { + collectionAdmin: true, + }, + }], + }); + const token = await collection.mintToken(alice); + await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]); - const address = collectionIdToAddress(collection); - const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS}); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(address, 'nft', caller); - const value = await contract.methods.property(token, 'testKey').call(); - expect(value).to.equal(web3.utils.toHex('testValue')); + const value = await contract.methods.property(token.tokenId, 'testKey').call(); + expect(value).to.equal(helper.getWeb3().utils.toHex('testValue')); }); }); + + +type ElementOf = A extends readonly (infer T)[] ? T : never; +function* cartesian>, R extends Array>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf}]> { + if(args.length === 0) { + yield internalRest as any; + return; + } + for(const value of args[0]) { + yield* cartesian([...internalRest, value], ...args.slice(1)) as any; + } +} \ No newline at end of file --- a/tests/src/eth/util/playgrounds/types.ts +++ b/tests/src/eth/util/playgrounds/types.ts @@ -6,4 +6,10 @@ export interface CompiledContract { abi: any; object: string; -} \ No newline at end of file +} + +export type NormalizedEvent = { + address: string, + event: string, + args: { [key: string]: string } +}; --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -18,7 +18,7 @@ import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev'; -import {ContractImports, CompiledContract} from './types'; +import {ContractImports, CompiledContract, NormalizedEvent} from './types'; // Native contracts ABI import collectionHelpersAbi from '../../collectionHelpersAbi.json'; @@ -252,6 +252,33 @@ return before - after; } + + normalizeEvents(events: any): NormalizedEvent[] { + const output = []; + for (const key of Object.keys(events)) { + if (key.match(/^[0-9]+$/)) { + output.push(events[key]); + } else if (Array.isArray(events[key])) { + output.push(...events[key]); + } else { + output.push(events[key]); + } + } + output.sort((a, b) => a.logIndex - b.logIndex); + return output.map(({address, event, returnValues}) => { + const args: { [key: string]: string } = {}; + for (const key of Object.keys(returnValues)) { + if (!key.match(/^[0-9]+$/)) { + args[key] = returnValues[key]; + } + } + return { + address, + event, + args, + }; + }); + } } class EthAddressGroup extends EthGroupBase {