git.delta.rocks / unique-network / refs/commits / 667f02faac6f

difftreelog

source

js-packages/tests/eth/allowlist.test.ts11.6 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 type {IKeyringPair} from '@polkadot/types/types';18import {Pallets} from '@unique/test-utils/util.js';19import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util/index.js';20import {CreateCollectionData} from './util/playgrounds/types.js';2122describe('EVM contract allowlist', () => {23  let donor: IKeyringPair;2425  before(async function() {26    await usingEthPlaygrounds(async (_helper, privateKey) => {27      donor = await privateKey({url: import.meta.url});28    });29  });3031  itEth('Contract allowlist can be toggled', async ({helper}) => {32    const owner = await helper.eth.createAccountWithBalance(donor);33    const flipper = await helper.eth.deployFlipper(owner);34    const helpers = helper.ethNativeContract.contractHelpers(owner);3536    // Any user is allowed by default37    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;3839    // Enable40    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});41    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.true;4243    // Disable44    await helpers.methods.toggleAllowlist(flipper.options.address, false).send({from: owner});45    expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false;46  });4748  itEth('Non-allowlisted user can\'t call contract with allowlist enabled', async ({helper}) => {49    const owner = await helper.eth.createAccountWithBalance(donor);50    const caller = await helper.eth.createAccountWithBalance(donor);51    const flipper = await helper.eth.deployFlipper(owner);52    const helpers = await helper.ethNativeContract.contractHelpers(owner);5354    // User can flip with allowlist disabled55    await flipper.methods.flip().send({from: caller});56    expect(await flipper.methods.getValue().call()).to.be.true;5758    // Tx will be reverted if user is not in allowlist59    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});60    await expect(flipper.methods.flip().send({from: caller})).to.rejected;61    expect(await flipper.methods.getValue().call()).to.be.true;6263    // Adding caller to allowlist will make contract callable again64    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});65    await flipper.methods.flip().send({from: caller});66    expect(await flipper.methods.getValue().call()).to.be.false;67  });68});6970describe('EVM collection allowlist', () => {71  let donor: IKeyringPair;7273  before(async function() {74    await usingEthPlaygrounds(async (_helper, privateKey) => {75      donor = await privateKey({url: import.meta.url});76    });77  });7879  // Soft-deprecated80  itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => {81    const owner = await helper.eth.createAccountWithBalance(donor);82    const user = helper.eth.createAccount();83    const crossUser = helper.ethCrossAccount.fromAddress(user);8485    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');86    const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);8788    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;89    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});90    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;9192    await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner});93    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;94  });959697  [98    {mode: 'nft' as const, requiredPallets: []},99    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},100    {mode: 'ft' as const, requiredPallets: []},101  ].map(testCase =>102    itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {103      const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();104      const [userSub] = await helper.arrange.createAccounts([10n], donor);105      const userEth = await helper.eth.createAccountWithBalance(donor);106      const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth];107108      const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();109      const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner);110      const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);111      const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);112      const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);113114      // Can addToCollectionAllowListCross:115      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;116      await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner});117      await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});118      await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});119120      // Accounts are in allowed list:121      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;122      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;123      expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;124      expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;125126      await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1127      await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2128      await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner});129130      // allowlisted account can transfer and transferCross from eth:131      await collectionEvm.methods.transfer(owner, 1).send({from: userEth});132      await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});133134      if(testCase.mode === 'ft') {135        expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n);136        expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n);137      } else {138        expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});139        expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});140      }141142      // allowlisted cross substrate accounts can transfer from Substrate:143      testCase.mode === 'ft'144        ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n)145        : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth});146147      // can removeFromCollectionAllowListCross:148      await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});149      await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner});150      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;151      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;152      expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false;153      expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;154155      // cannot transfer anymore156      await collectionEvm.methods.mint(...mintParams).send({from: owner});157      await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);158    }));159160  [161    // cross-methods162    {mode: 'nft' as const, cross: true, requiredPallets: []},163    {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]},164    {mode: 'ft' as const, cross: true, requiredPallets: []},165    // soft-deprecated166    {mode: 'nft' as const, cross: false, requiredPallets: []},167    {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]},168    {mode: 'ft' as const, cross: false, requiredPallets: []},169  ].map(testCase =>170    itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => {171      // Select methods:172      const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList';173      const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList';174175      const owner = await helper.eth.createAccountWithBalance(donor);176      const notOwner = await helper.eth.createAccountWithBalance(donor);177      const userSub = donor;178      const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);179      const userEth = helper.eth.createAccount();180      const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);181182      const {collectionAddress, collectionId} = await helper.eth.createCollection(owner, new CreateCollectionData('A', 'B', 'C', testCase.mode)).send();183      const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);184185      expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;186      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;187188      // 1. notOwner cannot add to allow list:189      // 1.1 plain ethereum or cross address:190      await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');191      // 1.2 cross-substrate address:192      if(testCase.cross)193        await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');194195      // 2. owner can add to allow list:196      // 2.1 plain ethereum or cross address:197      await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner});198      // 2.2 cross-substrate address:199      if(testCase.cross) {200        await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner});201        expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;202      }203      expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;204205      // 3. notOwner cannot remove from allow list:206      // 3.1 plain ethereum or cross address:207      await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission');208      // 3.2 cross-substrate address:209      if(testCase.cross)210        await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission');211    }));212});