git.delta.rocks / unique-network / refs/commits / c2beece34687

difftreelog

source

tests/src/eth/contractSponsoring.test.ts15.4 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {expect} from 'chai';18import {19  contractHelpers,20  createEthAccountWithBalance,21  transferBalanceToEth,22  deployFlipper,23  itWeb3,24  SponsoringMode,25  createEthAccount,26  collectionIdToAddress,27  GAS_ARGS,28  normalizeEvents,29  subToEth,30  executeEthTxOnSub,31  evmCollectionHelpers,32  getCollectionAddressFromResult,33  evmCollection,34} from './util/helpers';35import {36  addCollectionAdminExpectSuccess,37  createCollectionExpectSuccess,38  getDetailedCollectionInfo,39  transferBalanceTo,40} from '../util/helpers';41import nonFungibleAbi from './nonFungibleAbi.json';42import getBalance from '../substrate/get-balance';43import {evmToAddress} from '@polkadot/util-crypto';4445describe('Sponsoring EVM contracts', () => {46  itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {47    const owner = await createEthAccountWithBalance(api, web3);48    const flipper = await deployFlipper(web3, owner);49    const helpers = contractHelpers(web3, owner);50    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;51    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});52    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;53  });5455  itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {56    const owner = await createEthAccountWithBalance(api, web3);57    const notOwner = await createEthAccountWithBalance(api, web3);58    const flipper = await deployFlipper(web3, owner);59    const helpers = contractHelpers(web3, owner);60    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;61    await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;62    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;63  });6465  itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {66    const alice = privateKeyWrapper('//Alice');6768    const owner = await createEthAccountWithBalance(api, web3);69    const caller = await createEthAccountWithBalance(api, web3);7071    const flipper = await deployFlipper(web3, owner);7273    const helpers = contractHelpers(web3, owner);7475    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;76    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});77    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});78    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;7980    await transferBalanceToEth(api, alice, flipper.options.address);8182    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);83    expect(originalFlipperBalance).to.be.not.equal('0');8485    await flipper.methods.flip().send({from: caller});86    expect(await flipper.methods.getValue().call()).to.be.true;8788    // Balance should be taken from flipper instead of caller89    const balanceAfter = await web3.eth.getBalance(flipper.options.address);90    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);91  });9293  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}) => {94    const alice = privateKeyWrapper('//Alice');9596    const owner = await createEthAccountWithBalance(api, web3);97    const caller = createEthAccount(web3);9899    const flipper = await deployFlipper(web3, owner);100101    const helpers = contractHelpers(web3, owner);102    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});103    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});104105    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;106    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});107    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});108    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;109110    await transferBalanceToEth(api, alice, flipper.options.address);111112    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);113    expect(originalFlipperBalance).to.be.not.equal('0');114115    await flipper.methods.flip().send({from: caller});116    expect(await flipper.methods.getValue().call()).to.be.true;117118    // Balance should be taken from flipper instead of caller119    const balanceAfter = await web3.eth.getBalance(flipper.options.address);120    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);121  });122123  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}) => {124    const alice = privateKeyWrapper('//Alice');125126    const owner = await createEthAccountWithBalance(api, web3);127    const caller = createEthAccount(web3);128129    const flipper = await deployFlipper(web3, owner);130131    const helpers = contractHelpers(web3, owner);132133    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;134    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});135    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});136    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;137138    await transferBalanceToEth(api, alice, flipper.options.address);139140    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);141    expect(originalFlipperBalance).to.be.not.equal('0');142143    await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);144    expect(await flipper.methods.getValue().call()).to.be.false;145146    // Balance should be taken from flipper instead of caller147    const balanceAfter = await web3.eth.getBalance(flipper.options.address);148    expect(+balanceAfter).to.be.equals(+originalFlipperBalance);149  });150151  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}) => {152    const alice = privateKeyWrapper('//Alice');153154    const owner = await createEthAccountWithBalance(api, web3);155    const caller = await createEthAccountWithBalance(api, web3);156    const originalCallerBalance = await web3.eth.getBalance(caller);157158    const flipper = await deployFlipper(web3, owner);159160    const helpers = contractHelpers(web3, owner);161    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});162    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});163164    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;165    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});166    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});167    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;168169    await transferBalanceToEth(api, alice, flipper.options.address);170171    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);172    expect(originalFlipperBalance).to.be.not.equal('0');173174    await flipper.methods.flip().send({from: caller});175    expect(await flipper.methods.getValue().call()).to.be.true;176177    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);178  });179180  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}) => {181    const alice = privateKeyWrapper('//Alice');182183    const owner = await createEthAccountWithBalance(api, web3);184    const caller = await createEthAccountWithBalance(api, web3);185    const originalCallerBalance = await web3.eth.getBalance(caller);186187    const flipper = await deployFlipper(web3, owner);188189    const helpers = contractHelpers(web3, owner);190    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});191    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});192193    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;194    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});195    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});196    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;197198    await transferBalanceToEth(api, alice, flipper.options.address);199200    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);201    expect(originalFlipperBalance).to.be.not.equal('0');202203    await flipper.methods.flip().send({from: caller});204    expect(await flipper.methods.getValue().call()).to.be.true;205    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);206207    const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);208    expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);209210    await flipper.methods.flip().send({from: caller});211    expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);212    expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);213  });214215  // TODO: Find a way to calculate default rate limit216  itWeb3('Default rate limit equals 7200', async ({api, web3}) => {217    const owner = await createEthAccountWithBalance(api, web3);218    const flipper = await deployFlipper(web3, owner);219    const helpers = contractHelpers(web3, owner);220    expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');221  });222223  //TODO: CORE-302 add eth methods224  itWeb3.skip('Sponsoring evm address from substrate collection', async ({api, web3}) => {225    const owner = await createEthAccountWithBalance(api, web3);226    const collectionHelpers = evmCollectionHelpers(web3, owner);227    let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();228    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);229    const sponsor = await createEthAccountWithBalance(api, web3);230    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);231    result = await collectionEvm.methods.ethSetSponsor(sponsor).send();232    let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;233    expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;234    expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));235    await expect(collectionEvm.methods.ethConfirmSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236237    const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);238    await sponsorCollection.methods.ethConfirmSponsorship().send();239    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;240    expect(collectionSub.sponsorship.isConfirmed).to.be.true;241    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));242243    const user = createEthAccount(web3);244    const userContract = evmCollection(web3, user, collectionIdAddress);245    const nextTokenId = await userContract.methods.nextTokenId().call();246247    expect(nextTokenId).to.be.equal('1');248    await expect(userContract.methods.mintWithTokenURI(249      user,250      nextTokenId,251      'Test URI',252    ).call()).to.be.rejectedWith('PublicMintingNotAllowed');253    254    // TODO: add this methods to eth255    // {256    //   const tx = api.tx.unique.setPublicAccessMode(collectionId, 'AllowList');257    //   const events = await submitTransactionAsync(owner, tx);258    //   const result = getCreateCollectionResult(events);259    //   expect(result.success).to.be.true;260    // }261    // {262    //   const tx = api.tx.unique.addToAllowList(collectionId, {Ethereum: userEth});263    //   const events = await submitTransactionAsync(owner, tx);264    //   const result = getCreateCollectionResult(events);265    //   expect(result.success).to.be.true;266    // }267    // {268    //   const tx = api.tx.unique.setMintPermission(collectionId, true);269    //   const events = await submitTransactionAsync(owner, tx);270    //   const result = getCreateCollectionResult(events);271    //   expect(result.success).to.be.true;272    // }273274    // const [alicesBalanceBefore] = await getBalance(api, [alicesPublicKey]);275276    {277      const nextTokenId = await userContract.methods.nextTokenId().call();278      expect(nextTokenId).to.be.equal('1');279      const result = await userContract.methods.mintWithTokenURI(280        user,281        nextTokenId,282        'Test URI',283      ).send();284      const events = normalizeEvents(result.events);285286      expect(events).to.be.deep.equal([287        {288          collectionIdAddress,289          event: 'Transfer',290          args: {291            from: '0x0000000000000000000000000000000000000000',292            to: user,293            tokenId: nextTokenId,294          },295        },296      ]);297298      expect(await userContract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');299    }300  });301302  //TODO: CORE-302 add eth methods303  itWeb3.skip('Check that transaction via EVM spend money from substrate address', async ({api, web3, privateKeyWrapper}) => {304    const owner = privateKeyWrapper('//Alice');305    const user = privateKeyWrapper(`//User/${Date.now()}`);306    const userEth = subToEth(user.address);307    const collectionId = await createCollectionExpectSuccess();308    await addCollectionAdminExpectSuccess(owner, collectionId, {Ethereum: userEth});309    await transferBalanceTo(api, owner, user.address);310311    const address = collectionIdToAddress(collectionId);312    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: userEth, ...GAS_ARGS});313314    const [userBalanceBefore] = await getBalance(api, [user.address]);315316    {317      const nextTokenId = await contract.methods.nextTokenId().call();318      expect(nextTokenId).to.be.equal('1');319      await executeEthTxOnSub(web3, api, user, contract, m => m.mintWithTokenURI(320        userEth,321        nextTokenId,322        'Test URI',323      ));324325      expect(await contract.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');326    }327328    const [userBalanceAfter] = await getBalance(api, [user.address]);329    expect(userBalanceAfter < userBalanceBefore).to.be.true;330  });331});