difftreelog
Add required pallets
in: master
1 file changed
tests/src/eth/allowlist.test.tsdiffbeforeafterboth1// 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 = 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 = 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);83 84 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');85 const collectionEvm = 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(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, 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];106 107 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');108 const collectionEvm = 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);112 113 // 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;124 125 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});128 129 // 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});145 146 // 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;153 154 // 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(`Non-owner cannot add or remove from collection allowlist ${testCase.cross'cross '''}${testCase.mode}`, 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 = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);183 184 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;185 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;186 187 // 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;203 204 // 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});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 = 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 = 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);83 84 const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');85 const collectionEvm = 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];106 107 const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C');108 const collectionEvm = 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);112 113 // 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;124 125 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});128 129 // 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});145 146 // 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;153 154 // 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 = helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross);183 184 expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;185 expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;186 187 // 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;203 204 // 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});