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

difftreelog

source

tests/src/eth/allowlist.test.ts11.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 {IKeyringPair} from '@polkadot/types/types';18import {Pallets} from '../util';19import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util';2021describe('EVM contract allowlist', () => {22  let donor: IKeyringPair;2324  before(async function() {25    await usingEthPlaygrounds(async (_helper, privateKey) => {26      donor = await privateKey({filename: __filename});27    });28  });2930  itEth('Contract allowlist can be toggled', async ({helper}) => {31    const owner = await helper.eth.createAccountWithBalance(donor);32    const flipper = await helper.eth.deployFlipper(owner);33    const helpers = await helper.ethNativeContract.contractHelpers(owner);3435    // Any user is allowed by default36    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;3738    // Enable39    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});40    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.true;4142    // Disable43    await helpers.methods.toggleAllowlist(flipper.options.address, false).send({from: owner});44    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;45  });4647  itEth('Non-allowlisted user can\'t call contract with allowlist enabled', async ({helper}) => {48    const owner = await helper.eth.createAccountWithBalance(donor);49    const caller = await helper.eth.createAccountWithBalance(donor);50    const flipper = await helper.eth.deployFlipper(owner);51    const helpers = await helper.ethNativeContract.contractHelpers(owner);5253    // User can flip with allowlist disabled54    await flipper.methods.flip().send({from: caller});55    expect(await flipper.methods.getValue().call()).to.be.true;5657    // Tx will be reverted if user is not in allowlist58    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});59    await expect(flipper.methods.flip().send({from: caller})).to.rejected;60    expect(await flipper.methods.getValue().call()).to.be.true;6162    // Adding caller to allowlist will make contract callable again63    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});64    await flipper.methods.flip().send({from: caller});65    expect(await flipper.methods.getValue().call()).to.be.false;66  });67});6869describe('EVM collection allowlist', () => {70  let donor: IKeyringPair;7172  before(async function() {73    await usingEthPlaygrounds(async (_helper, privateKey) => {74      donor = await privateKey({filename: __filename});75    });76  });7778  // Soft-deprecated79  itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => {80    const owner = await helper.eth.createAccountWithBalance(donor);81    const user = helper.eth.createAccount();82    const crossUser = helper.ethCrossAccount.fromAddress(user);8384    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');85    const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);8687    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;88    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});89    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;9091    await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner});92    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;93  });949596  [97    {mode: 'nft' as const, requiredPallets: []},98    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},99    {mode: 'ft' as const, requiredPallets: []},100  ].map(testCase =>101    itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {102      const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();103      const [userSub] = await helper.arrange.createAccounts([10n], donor);104      const userEth = await helper.eth.createAccountWithBalance(donor);105      const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth];106107      const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');108      const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);109      const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);110      const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);111      const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);112113      // Can addToCollectionAllowListCross:114      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;115      await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner});116      await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});117      await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});118119      // Accounts are in allowed list:120      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;121      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;122      expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;123      expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;124125      await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1126      await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2127      await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner});128129      // allowlisted account can transfer and transferCross from eth:130      await collectionEvm.methods.transfer(owner, 1).send({from: userEth});131      await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});132133      if (testCase.mode === 'ft') {134        expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n);135        expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n);136      } else {137        expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});138        expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});139      }140141      // allowlisted cross substrate accounts can transfer from Substrate:142      testCase.mode === 'ft'143        ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n)144        : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth});145146      // can removeFromCollectionAllowListCross:147      await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});148      await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner});149      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;150      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;151      expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false;152      expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;153154      // cannot transfer anymore155      await collectionEvm.methods.mint(...mintParams).send({from: owner});156      await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);157    }));158159  [160    // cross-methods161    {mode: 'nft' as const, cross: true, requiredPallets: []},162    {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]},163    {mode: 'ft' as const, cross: true, requiredPallets: []},164    // soft-deprecated165    {mode: 'nft' as const, cross: false, requiredPallets: []},166    {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]},167    {mode: 'ft' as const, cross: false, requiredPallets: []},168  ].map(testCase =>169    itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {170      // Select methods:171      const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList';172      const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList';173174      const owner = await helper.eth.createAccountWithBalance(donor);175      const notOwner = await helper.eth.createAccountWithBalance(donor);176      const userSub = donor;177      const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);178      const userEth = helper.eth.createAccount();179      const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);180181      const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');182      const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);183184      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;185      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;186187      // 1. notOwner cannot add to allow list:188      // 1.1 plain ethereum or cross address:189      await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');190      // 1.2 cross-substrate address:191      if (testCase.cross)192        await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');193194      // 2. owner can add to allow list:195      // 2.1 plain ethereum or cross address:196      await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner});197      // 2.2 cross-substrate address:198      if (testCase.cross) {199        await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner});200        expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;201      }202      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;203204      // 3. notOwner cannot remove from allow list:205      // 3.1 plain ethereum or cross address:206      await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');207      // 3.2 cross-substrate address:208      if (testCase.cross)209        await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');210    }));211});