git.delta.rocks / unique-network / refs/commits / 87ff08974106

difftreelog

CORE-386 Fix PR

Trubnikov Sergey2022-06-03parent: #9e201d9.patch.diff
in: master

7 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -261,13 +261,13 @@
 		Ok(())
 	}
 
-	fn set_collection_access(&mut self, caller: caller, mode: string) -> Result<void> {
+	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		self.check_is_owner_or_admin(&caller)
 			.map_err(dispatch_to_evm::<T>)?;
-		self.collection.permissions.access = Some(match mode.as_str() {
-			"Normal" => AccessMode::Normal,
-			"AllowList" => AccessMode::AllowList,
+		self.collection.permissions.access = Some(match mode {
+			0 => AccessMode::Normal,
+			1 => AccessMode::AllowList,
 			_ => return Err("Not supported access mode".into()),
 		});
 		save(self);
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -543,6 +543,7 @@
 				token_owner,
 				..
 			} => {
+				//TODO: исследовать угрозы при публичном минтинге.
 				if is_token_create && (collection_admin || token_owner) {
 					return Ok(());
 				}
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -51,135 +51,6 @@
 	event MintingFinished();
 }
 
-// Selector: 1248b7d1
-contract Collection is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		public
-	{
-		require(false, stub_error);
-		key;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) public {
-		require(false, stub_error);
-		key;
-		dummy = 0;
-	}
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		public
-		view
-		returns (bytes memory)
-	{
-		require(false, stub_error);
-		key;
-		dummy;
-		return hex"";
-	}
-
-	// Selector: setCollectionSponsor(address) 7623402e
-	function setCollectionSponsor(address sponsor) public {
-		require(false, stub_error);
-		sponsor;
-		dummy = 0;
-	}
-
-	// Selector: confirmCollectionSponsorship() 3c50e97a
-	function confirmCollectionSponsorship() public {
-		require(false, stub_error);
-		dummy = 0;
-	}
-
-	// Selector: setCollectionLimit(string,uint32) 6a3841db
-	function setCollectionLimit(string memory limit, uint32 value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: setCollectionLimit(string,bool) 993b7fba
-	function setCollectionLimit(string memory limit, bool value) public {
-		require(false, stub_error);
-		limit;
-		value;
-		dummy = 0;
-	}
-
-	// Selector: contractAddress() f6b4dfb4
-	function contractAddress() public view returns (address) {
-		require(false, stub_error);
-		dummy;
-		return 0x0000000000000000000000000000000000000000;
-	}
-
-	// Selector: addCollectionAdmin(address) 92e462c7
-	function addCollectionAdmin(address newAdmin) public view {
-		require(false, stub_error);
-		newAdmin;
-		dummy;
-	}
-
-	// Selector: removeCollectionAdmin(address) fafd7b42
-	function removeCollectionAdmin(address admin) public view {
-		require(false, stub_error);
-		admin;
-		dummy;
-	}
-
-	// Selector: setCollectionNesting(bool) 112d4586
-	function setCollectionNesting(bool enable) public {
-		require(false, stub_error);
-		enable;
-		dummy = 0;
-	}
-
-	// Selector: setCollectionNesting(bool,address[]) 64872396
-	function setCollectionNesting(bool enable, address[] memory collections)
-		public
-	{
-		require(false, stub_error);
-		enable;
-		collections;
-		dummy = 0;
-	}
-
-	// Selector: setCollectionAccess(string) 392172a9
-	function setCollectionAccess(string memory mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-
-	// Selector: addToCollectionAllowList(address) 67844fe6
-	function addToCollectionAllowList(address user) public view {
-		require(false, stub_error);
-		user;
-		dummy;
-	}
-
-	// Selector: removeFromCollectionAllowList(address) 85c51acb
-	function removeFromCollectionAllowList(address user) public view {
-		require(false, stub_error);
-		user;
-		dummy;
-	}
-
-	// Selector: setCollectionMintMode(bool) 00018e84
-	function setCollectionMintMode(bool mode) public {
-		require(false, stub_error);
-		mode;
-		dummy = 0;
-	}
-}
-
 // Selector: 41369377
 contract TokenProperties is Dummy, ERC165 {
 	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
@@ -426,6 +297,135 @@
 	}
 }
 
+// Selector: 6aea9834
+contract Collection is Dummy, ERC165 {
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		public
+	{
+		require(false, stub_error);
+		key;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) public {
+		require(false, stub_error);
+		key;
+		dummy = 0;
+	}
+
+	// Throws error if key not found
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		public
+		view
+		returns (bytes memory)
+	{
+		require(false, stub_error);
+		key;
+		dummy;
+		return hex"";
+	}
+
+	// Selector: setCollectionSponsor(address) 7623402e
+	function setCollectionSponsor(address sponsor) public {
+		require(false, stub_error);
+		sponsor;
+		dummy = 0;
+	}
+
+	// Selector: confirmCollectionSponsorship() 3c50e97a
+	function confirmCollectionSponsorship() public {
+		require(false, stub_error);
+		dummy = 0;
+	}
+
+	// Selector: setCollectionLimit(string,uint32) 6a3841db
+	function setCollectionLimit(string memory limit, uint32 value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: setCollectionLimit(string,bool) 993b7fba
+	function setCollectionLimit(string memory limit, bool value) public {
+		require(false, stub_error);
+		limit;
+		value;
+		dummy = 0;
+	}
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+
+	// Selector: addCollectionAdmin(address) 92e462c7
+	function addCollectionAdmin(address newAdmin) public view {
+		require(false, stub_error);
+		newAdmin;
+		dummy;
+	}
+
+	// Selector: removeCollectionAdmin(address) fafd7b42
+	function removeCollectionAdmin(address admin) public view {
+		require(false, stub_error);
+		admin;
+		dummy;
+	}
+
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) public {
+		require(false, stub_error);
+		enable;
+		dummy = 0;
+	}
+
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		public
+	{
+		require(false, stub_error);
+		enable;
+		collections;
+		dummy = 0;
+	}
+
+	// Selector: setCollectionAccess(uint8) 41835d4c
+	function setCollectionAccess(uint8 mode) public {
+		require(false, stub_error);
+		mode;
+		dummy = 0;
+	}
+
+	// Selector: addToCollectionAllowList(address) 67844fe6
+	function addToCollectionAllowList(address user) public view {
+		require(false, stub_error);
+		user;
+		dummy;
+	}
+
+	// Selector: removeFromCollectionAllowList(address) 85c51acb
+	function removeFromCollectionAllowList(address user) public view {
+		require(false, stub_error);
+		user;
+		dummy;
+	}
+
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) public {
+		require(false, stub_error);
+		mode;
+		dummy = 0;
+	}
+}
+
 // Selector: 780e9d63
 contract ERC721Enumerable is Dummy, ERC165 {
 	// Selector: tokenByIndex(uint256) 4f6ccce7
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -42,64 +42,6 @@
 	event MintingFinished();
 }
 
-// Selector: 1248b7d1
-interface Collection is Dummy, ERC165 {
-	// Selector: setCollectionProperty(string,bytes) 2f073f66
-	function setCollectionProperty(string memory key, bytes memory value)
-		external;
-
-	// Selector: deleteCollectionProperty(string) 7b7debce
-	function deleteCollectionProperty(string memory key) external;
-
-	// Throws error if key not found
-	//
-	// Selector: collectionProperty(string) cf24fd6d
-	function collectionProperty(string memory key)
-		external
-		view
-		returns (bytes memory);
-
-	// Selector: setCollectionSponsor(address) 7623402e
-	function setCollectionSponsor(address sponsor) external;
-
-	// Selector: confirmCollectionSponsorship() 3c50e97a
-	function confirmCollectionSponsorship() external;
-
-	// Selector: setCollectionLimit(string,uint32) 6a3841db
-	function setCollectionLimit(string memory limit, uint32 value) external;
-
-	// Selector: setCollectionLimit(string,bool) 993b7fba
-	function setCollectionLimit(string memory limit, bool value) external;
-
-	// Selector: contractAddress() f6b4dfb4
-	function contractAddress() external view returns (address);
-
-	// Selector: addCollectionAdmin(address) 92e462c7
-	function addCollectionAdmin(address newAdmin) external view;
-
-	// Selector: removeCollectionAdmin(address) fafd7b42
-	function removeCollectionAdmin(address admin) external view;
-
-	// Selector: setCollectionNesting(bool) 112d4586
-	function setCollectionNesting(bool enable) external;
-
-	// Selector: setCollectionNesting(bool,address[]) 64872396
-	function setCollectionNesting(bool enable, address[] memory collections)
-		external;
-
-	// Selector: setCollectionAccess(string) 392172a9
-	function setCollectionAccess(string memory mode) external;
-
-	// Selector: addToCollectionAllowList(address) 67844fe6
-	function addToCollectionAllowList(address user) external view;
-
-	// Selector: removeFromCollectionAllowList(address) 85c51acb
-	function removeFromCollectionAllowList(address user) external view;
-
-	// Selector: setCollectionMintMode(bool) 00018e84
-	function setCollectionMintMode(bool mode) external;
-}
-
 // Selector: 41369377
 interface TokenProperties is Dummy, ERC165 {
 	// Selector: setTokenPropertyPermission(string,bool,bool,bool) 222d97fa
@@ -232,6 +174,64 @@
 	function finishMinting() external returns (bool);
 }
 
+// Selector: 6aea9834
+interface Collection is Dummy, ERC165 {
+	// Selector: setCollectionProperty(string,bytes) 2f073f66
+	function setCollectionProperty(string memory key, bytes memory value)
+		external;
+
+	// Selector: deleteCollectionProperty(string) 7b7debce
+	function deleteCollectionProperty(string memory key) external;
+
+	// Throws error if key not found
+	//
+	// Selector: collectionProperty(string) cf24fd6d
+	function collectionProperty(string memory key)
+		external
+		view
+		returns (bytes memory);
+
+	// Selector: setCollectionSponsor(address) 7623402e
+	function setCollectionSponsor(address sponsor) external;
+
+	// Selector: confirmCollectionSponsorship() 3c50e97a
+	function confirmCollectionSponsorship() external;
+
+	// Selector: setCollectionLimit(string,uint32) 6a3841db
+	function setCollectionLimit(string memory limit, uint32 value) external;
+
+	// Selector: setCollectionLimit(string,bool) 993b7fba
+	function setCollectionLimit(string memory limit, bool value) external;
+
+	// Selector: contractAddress() f6b4dfb4
+	function contractAddress() external view returns (address);
+
+	// Selector: addCollectionAdmin(address) 92e462c7
+	function addCollectionAdmin(address newAdmin) external view;
+
+	// Selector: removeCollectionAdmin(address) fafd7b42
+	function removeCollectionAdmin(address admin) external view;
+
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) external;
+
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		external;
+
+	// Selector: setCollectionAccess(uint8) 41835d4c
+	function setCollectionAccess(uint8 mode) external;
+
+	// Selector: addToCollectionAllowList(address) 67844fe6
+	function addToCollectionAllowList(address user) external view;
+
+	// Selector: removeFromCollectionAllowList(address) 85c51acb
+	function removeFromCollectionAllowList(address user) external view;
+
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) external;
+}
+
 // Selector: 780e9d63
 interface ERC721Enumerable is Dummy, ERC165 {
 	// Selector: tokenByIndex(uint256) 4f6ccce7
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
before · tests/src/eth/contractSponsoring.test.ts
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  ethBalanceViaSub,35} from './util/helpers';36import {37  addCollectionAdminExpectSuccess,38  createCollectionExpectSuccess,39  getDetailedCollectionInfo,40  transferBalanceTo,41} from '../util/helpers';42import nonFungibleAbi from './nonFungibleAbi.json';43import getBalance from '../substrate/get-balance';44import {evmToAddress} from '@polkadot/util-crypto';4546describe('Sponsoring EVM contracts', () => {47  itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {48    const owner = await createEthAccountWithBalance(api, web3);49    const flipper = await deployFlipper(web3, owner);50    const helpers = contractHelpers(web3, owner);51    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;52    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});53    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;54  });5556  itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {57    const owner = await createEthAccountWithBalance(api, web3);58    const notOwner = await createEthAccountWithBalance(api, web3);59    const flipper = await deployFlipper(web3, owner);60    const helpers = contractHelpers(web3, owner);61    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;62    await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;63    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;64  });6566  itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {67    const alice = privateKeyWrapper('//Alice');6869    const owner = await createEthAccountWithBalance(api, web3);70    const caller = await createEthAccountWithBalance(api, web3);7172    const flipper = await deployFlipper(web3, owner);7374    const helpers = contractHelpers(web3, owner);7576    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;77    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});78    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});79    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;8081    await transferBalanceToEth(api, alice, flipper.options.address);8283    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);84    expect(originalFlipperBalance).to.be.not.equal('0');8586    await flipper.methods.flip().send({from: caller});87    expect(await flipper.methods.getValue().call()).to.be.true;8889    // Balance should be taken from flipper instead of caller90    const balanceAfter = await web3.eth.getBalance(flipper.options.address);91    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);92  });9394  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}) => {95    const alice = privateKeyWrapper('//Alice');9697    const owner = await createEthAccountWithBalance(api, web3);98    const caller = createEthAccount(web3);99100    const flipper = await deployFlipper(web3, owner);101102    const helpers = contractHelpers(web3, owner);103    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});104    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});105106    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;107    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});108    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});109    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;110111    await transferBalanceToEth(api, alice, flipper.options.address);112113    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);114    expect(originalFlipperBalance).to.be.not.equal('0');115116    await flipper.methods.flip().send({from: caller});117    expect(await flipper.methods.getValue().call()).to.be.true;118119    // Balance should be taken from flipper instead of caller120    const balanceAfter = await web3.eth.getBalance(flipper.options.address);121    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);122  });123124  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}) => {125    const alice = privateKeyWrapper('//Alice');126127    const owner = await createEthAccountWithBalance(api, web3);128    const caller = createEthAccount(web3);129130    const flipper = await deployFlipper(web3, owner);131132    const helpers = contractHelpers(web3, owner);133134    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;135    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});136    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});137    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;138139    await transferBalanceToEth(api, alice, flipper.options.address);140141    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);142    expect(originalFlipperBalance).to.be.not.equal('0');143144    await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);145    expect(await flipper.methods.getValue().call()).to.be.false;146147    // Balance should be taken from flipper instead of caller148    const balanceAfter = await web3.eth.getBalance(flipper.options.address);149    expect(+balanceAfter).to.be.equals(+originalFlipperBalance);150  });151152  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}) => {153    const alice = privateKeyWrapper('//Alice');154155    const owner = await createEthAccountWithBalance(api, web3);156    const caller = await createEthAccountWithBalance(api, web3);157    const originalCallerBalance = await web3.eth.getBalance(caller);158159    const flipper = await deployFlipper(web3, owner);160161    const helpers = contractHelpers(web3, owner);162    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});163    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});164165    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;166    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});167    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});168    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;169170    await transferBalanceToEth(api, alice, flipper.options.address);171172    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);173    expect(originalFlipperBalance).to.be.not.equal('0');174175    await flipper.methods.flip().send({from: caller});176    expect(await flipper.methods.getValue().call()).to.be.true;177178    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);179  });180181  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}) => {182    const alice = privateKeyWrapper('//Alice');183184    const owner = await createEthAccountWithBalance(api, web3);185    const caller = await createEthAccountWithBalance(api, web3);186    const originalCallerBalance = await web3.eth.getBalance(caller);187188    const flipper = await deployFlipper(web3, owner);189190    const helpers = contractHelpers(web3, owner);191    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});192    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});193194    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;195    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});196    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});197    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;198199    await transferBalanceToEth(api, alice, flipper.options.address);200201    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);202    expect(originalFlipperBalance).to.be.not.equal('0');203204    await flipper.methods.flip().send({from: caller});205    expect(await flipper.methods.getValue().call()).to.be.true;206    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);207208    const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);209    expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);210211    await flipper.methods.flip().send({from: caller});212    expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);213    expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);214  });215216  // TODO: Find a way to calculate default rate limit217  itWeb3('Default rate limit equals 7200', async ({api, web3}) => {218    const owner = await createEthAccountWithBalance(api, web3);219    const flipper = await deployFlipper(web3, owner);220    const helpers = contractHelpers(web3, owner);221    expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');222  });223224  itWeb3('Sponsoring collection from evm address via access list', 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.setCollectionSponsor(sponsor).send({from: owner});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.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236237    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});238    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;239    expect(collectionSub.sponsorship.isConfirmed).to.be.true;240    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));241242    const user = createEthAccount(web3);243    let nextTokenId = await collectionEvm.methods.nextTokenId().call();244    expect(nextTokenId).to.be.equal('1');245246    const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();247    expect(oldPermissions.mintMode).to.be.false;248    expect(oldPermissions.access).to.be.equal('Normal');249250    await collectionEvm.methods.setCollectionAccess('AllowList').send({from: owner});251    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});252    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});253254    const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();255    expect(newPermissions.mintMode).to.be.true;256    expect(newPermissions.access).to.be.equal('AllowList');257258    const ownerBalanceBefore = await ethBalanceViaSub(api, owner);259    const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);260261    nextTokenId = await collectionEvm.methods.nextTokenId().call({from: user});262    expect(nextTokenId).to.be.equal('1');263    result = await collectionEvm.methods.mintWithTokenURI(264      user,265      nextTokenId,266      'Test URI',267    ).send({from: user});268    const events = normalizeEvents(result.events);269    events[0].address = events[0].address.toLocaleLowerCase();270271    expect(events).to.be.deep.equal([272      {273        address: collectionIdAddress.toLocaleLowerCase(),274        event: 'Transfer',275        args: {276          from: '0x0000000000000000000000000000000000000000',277          to: user,278          tokenId: nextTokenId,279        },280      },281    ]);282283    expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');284285    const ownerBalanceAfter = await ethBalanceViaSub(api, owner);286    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);287    const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);288    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;289  });290291  itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3}) => {292    const owner = await createEthAccountWithBalance(api, web3);293    const collectionHelpers = evmCollectionHelpers(web3, owner);294    let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();295    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);296    const sponsor = await createEthAccountWithBalance(api, web3);297    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);298    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();299    let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;300    expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;301    expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));302    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');303    const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);304    await sponsorCollection.methods.confirmCollectionSponsorship().send();305    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;306    expect(collectionSub.sponsorship.isConfirmed).to.be.true;307    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));308309    const user = createEthAccount(web3);310    await collectionEvm.methods.addCollectionAdmin(user).send();311    312    const ownerBalanceBefore = await ethBalanceViaSub(api, owner);313    const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);314  315    const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);316    const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();317    expect(nextTokenId).to.be.equal('1');318    result = await userCollectionEvm.methods.mintWithTokenURI(319      user,320      nextTokenId,321      'Test URI',322    ).send();323324    const events = normalizeEvents(result.events);325    const address = collectionIdToAddress(collectionId);326327    expect(events).to.be.deep.equal([328      {329        address,330        event: 'Transfer',331        args: {332          from: '0x0000000000000000000000000000000000000000',333          to: user,334          tokenId: nextTokenId,335        },336      },337    ]);338    expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');339  340    const ownerBalanceAfter = await ethBalanceViaSub(api, owner);341    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);342    const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);343    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;344  });345});
after · tests/src/eth/contractSponsoring.test.ts
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  ethBalanceViaSub,35} from './util/helpers';36import {37  addCollectionAdminExpectSuccess,38  createCollectionExpectSuccess,39  getDetailedCollectionInfo,40  transferBalanceTo,41} from '../util/helpers';42import nonFungibleAbi from './nonFungibleAbi.json';43import getBalance from '../substrate/get-balance';44import {evmToAddress} from '@polkadot/util-crypto';4546describe('Sponsoring EVM contracts', () => {47  itWeb3('Sponsoring can be set by the address that has deployed the contract', async ({api, web3}) => {48    const owner = await createEthAccountWithBalance(api, web3);49    const flipper = await deployFlipper(web3, owner);50    const helpers = contractHelpers(web3, owner);51    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;52    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});53    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;54  });5556  itWeb3('Sponsoring cannot be set by the address that did not deployed the contract', async ({api, web3}) => {57    const owner = await createEthAccountWithBalance(api, web3);58    const notOwner = await createEthAccountWithBalance(api, web3);59    const flipper = await deployFlipper(web3, owner);60    const helpers = contractHelpers(web3, owner);61    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;62    await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).send({from: notOwner})).to.rejected;63    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;64  });6566  itWeb3('In generous mode, non-allowlisted user transaction will be sponsored', async ({api, web3, privateKeyWrapper}) => {67    const alice = privateKeyWrapper('//Alice');6869    const owner = await createEthAccountWithBalance(api, web3);70    const caller = await createEthAccountWithBalance(api, web3);7172    const flipper = await deployFlipper(web3, owner);7374    const helpers = contractHelpers(web3, owner);7576    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;77    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner});78    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});79    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;8081    await transferBalanceToEth(api, alice, flipper.options.address);8283    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);84    expect(originalFlipperBalance).to.be.not.equal('0');8586    await flipper.methods.flip().send({from: caller});87    expect(await flipper.methods.getValue().call()).to.be.true;8889    // Balance should be taken from flipper instead of caller90    const balanceAfter = await web3.eth.getBalance(flipper.options.address);91    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);92  });9394  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}) => {95    const alice = privateKeyWrapper('//Alice');9697    const owner = await createEthAccountWithBalance(api, web3);98    const caller = createEthAccount(web3);99100    const flipper = await deployFlipper(web3, owner);101102    const helpers = contractHelpers(web3, owner);103    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});104    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});105106    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;107    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});108    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});109    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;110111    await transferBalanceToEth(api, alice, flipper.options.address);112113    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);114    expect(originalFlipperBalance).to.be.not.equal('0');115116    await flipper.methods.flip().send({from: caller});117    expect(await flipper.methods.getValue().call()).to.be.true;118119    // Balance should be taken from flipper instead of caller120    const balanceAfter = await web3.eth.getBalance(flipper.options.address);121    expect(+balanceAfter).to.be.lessThan(+originalFlipperBalance);122  });123124  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}) => {125    const alice = privateKeyWrapper('//Alice');126127    const owner = await createEthAccountWithBalance(api, web3);128    const caller = createEthAccount(web3);129130    const flipper = await deployFlipper(web3, owner);131132    const helpers = contractHelpers(web3, owner);133134    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;135    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});136    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});137    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;138139    await transferBalanceToEth(api, alice, flipper.options.address);140141    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);142    expect(originalFlipperBalance).to.be.not.equal('0');143144    await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);145    expect(await flipper.methods.getValue().call()).to.be.false;146147    // Balance should be taken from flipper instead of caller148    const balanceAfter = await web3.eth.getBalance(flipper.options.address);149    expect(+balanceAfter).to.be.equals(+originalFlipperBalance);150  });151152  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}) => {153    const alice = privateKeyWrapper('//Alice');154155    const owner = await createEthAccountWithBalance(api, web3);156    const caller = await createEthAccountWithBalance(api, web3);157    const originalCallerBalance = await web3.eth.getBalance(caller);158159    const flipper = await deployFlipper(web3, owner);160161    const helpers = contractHelpers(web3, owner);162    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});163    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});164165    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;166    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});167    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner});168    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;169170    await transferBalanceToEth(api, alice, flipper.options.address);171172    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);173    expect(originalFlipperBalance).to.be.not.equal('0');174175    await flipper.methods.flip().send({from: caller});176    expect(await flipper.methods.getValue().call()).to.be.true;177178    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);179  });180181  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}) => {182    const alice = privateKeyWrapper('//Alice');183184    const owner = await createEthAccountWithBalance(api, web3);185    const caller = await createEthAccountWithBalance(api, web3);186    const originalCallerBalance = await web3.eth.getBalance(caller);187188    const flipper = await deployFlipper(web3, owner);189190    const helpers = contractHelpers(web3, owner);191    await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner});192    await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner});193194    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false;195    await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner});196    await helpers.methods.setSponsoringRateLimit(flipper.options.address, 10).send({from: owner});197    expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true;198199    await transferBalanceToEth(api, alice, flipper.options.address);200201    const originalFlipperBalance = await web3.eth.getBalance(flipper.options.address);202    expect(originalFlipperBalance).to.be.not.equal('0');203204    await flipper.methods.flip().send({from: caller});205    expect(await flipper.methods.getValue().call()).to.be.true;206    expect(await web3.eth.getBalance(caller)).to.be.equals(originalCallerBalance);207208    const newFlipperBalance = await web3.eth.getBalance(flipper.options.address);209    expect(newFlipperBalance).to.be.not.equals(originalFlipperBalance);210211    await flipper.methods.flip().send({from: caller});212    expect(await web3.eth.getBalance(flipper.options.address)).to.be.equal(newFlipperBalance);213    expect(await web3.eth.getBalance(caller)).to.be.not.equals(originalCallerBalance);214  });215216  // TODO: Find a way to calculate default rate limit217  itWeb3('Default rate limit equals 7200', async ({api, web3}) => {218    const owner = await createEthAccountWithBalance(api, web3);219    const flipper = await deployFlipper(web3, owner);220    const helpers = contractHelpers(web3, owner);221    expect(await helpers.methods.getSponsoringRateLimit(flipper.options.address).call()).to.be.equals('7200');222  });223224  itWeb3('Sponsoring collection from evm address via access list', 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.setCollectionSponsor(sponsor).send({from: owner});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.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');236237    await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});238    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;239    expect(collectionSub.sponsorship.isConfirmed).to.be.true;240    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));241242    const user = createEthAccount(web3);243    let nextTokenId = await collectionEvm.methods.nextTokenId().call();244    expect(nextTokenId).to.be.equal('1');245246    const oldPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();247    expect(oldPermissions.mintMode).to.be.false;248    expect(oldPermissions.access).to.be.equal('Normal');249250    //TODO: change value, when enum generated251    await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});252    await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});253    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});254255    const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();256    expect(newPermissions.mintMode).to.be.true;257    expect(newPermissions.access).to.be.equal('AllowList');258259    const ownerBalanceBefore = await ethBalanceViaSub(api, owner);260    const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);261262    nextTokenId = await collectionEvm.methods.nextTokenId().call({from: user});263    expect(nextTokenId).to.be.equal('1');264    result = await collectionEvm.methods.mintWithTokenURI(265      user,266      nextTokenId,267      'Test URI',268    ).send({from: user});269    const events = normalizeEvents(result.events);270    events[0].address = events[0].address.toLocaleLowerCase();271272    expect(events).to.be.deep.equal([273      {274        address: collectionIdAddress.toLocaleLowerCase(),275        event: 'Transfer',276        args: {277          from: '0x0000000000000000000000000000000000000000',278          to: user,279          tokenId: nextTokenId,280        },281      },282    ]);283284    expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');285286    const ownerBalanceAfter = await ethBalanceViaSub(api, owner);287    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);288    const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);289    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;290  });291292  itWeb3('Check that transaction via EVM spend money from sponsor address', async ({api, web3}) => {293    const owner = await createEthAccountWithBalance(api, web3);294    const collectionHelpers = evmCollectionHelpers(web3, owner);295    let result = await collectionHelpers.methods.createNonfungibleCollection('Sponsor collection', '1', '1').send();296    const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);297    const sponsor = await createEthAccountWithBalance(api, web3);298    const collectionEvm = evmCollection(web3, owner, collectionIdAddress);299    result = await collectionEvm.methods.setCollectionSponsor(sponsor).send();300    let collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;301    expect(collectionSub.sponsorship.isUnconfirmed).to.be.true;302    expect(collectionSub.sponsorship.asUnconfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));303    await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('Caller is not set as sponsor');304    const sponsorCollection = evmCollection(web3, sponsor, collectionIdAddress);305    await sponsorCollection.methods.confirmCollectionSponsorship().send();306    collectionSub = (await getDetailedCollectionInfo(api, collectionId))!;307    expect(collectionSub.sponsorship.isConfirmed).to.be.true;308    expect(collectionSub.sponsorship.asConfirmed.toHuman()).to.be.eq(evmToAddress(sponsor));309310    const user = createEthAccount(web3);311    await collectionEvm.methods.addCollectionAdmin(user).send();312    313    const ownerBalanceBefore = await ethBalanceViaSub(api, owner);314    const sponsorBalanceBefore = await ethBalanceViaSub(api, sponsor);315  316    const userCollectionEvm = evmCollection(web3, user, collectionIdAddress);317    const nextTokenId = await userCollectionEvm.methods.nextTokenId().call();318    expect(nextTokenId).to.be.equal('1');319    result = await userCollectionEvm.methods.mintWithTokenURI(320      user,321      nextTokenId,322      'Test URI',323    ).send();324325    const events = normalizeEvents(result.events);326    const address = collectionIdToAddress(collectionId);327328    expect(events).to.be.deep.equal([329      {330        address,331        event: 'Transfer',332        args: {333          from: '0x0000000000000000000000000000000000000000',334          to: user,335          tokenId: nextTokenId,336        },337      },338    ]);339    expect(await userCollectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI');340  341    const ownerBalanceAfter = await ethBalanceViaSub(api, owner);342    expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore);343    const sponsorBalanceAfter = await ethBalanceViaSub(api, sponsor);344    expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true;345  });346});
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -341,7 +341,7 @@
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "string", "name": "mode", "type": "string" }],
+    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],
     "name": "setCollectionAccess",
     "outputs": [],
     "stateMutability": "nonpayable",