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

difftreelog

added repartition method to refungible erc20 extensions

Grigoriy Simonov2022-07-22parent: #4fbe604.patch.diff
in: master

7 files changed

modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -1,3 +1,19 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
 extern crate alloc;
 use evm_coder::{generate_stubgen, solidity_interface, types::*};
 
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -149,6 +149,15 @@
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
 	}
+
+	#[weight(<SelfWeightOf<T>>::repartition_item())]
+	fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Pallet<T>>::repartition(self, &caller, self.1, amount).map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
 }
 
 impl<T: Config> RefungibleTokenHandle<T> {
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungibleToken.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol
@@ -31,18 +31,6 @@
 	);
 }
 
-// Selector: 79cc6790
-contract ERC20UniqueExtensions is Dummy, ERC165 {
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		from;
-		amount;
-		dummy = 0;
-		return false;
-	}
-}
-
 // Selector: 942e8b22
 contract ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
@@ -127,4 +115,24 @@
 	}
 }
 
+// Selector: ab8deb37
+contract ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		from;
+		amount;
+		dummy = 0;
+		return false;
+	}
+
+	// Selector: repartition(uint256) d2418ca7
+	function repartition(uint256 amount) public returns (bool) {
+		require(false, stub_error);
+		amount;
+		dummy = 0;
+		return false;
+	}
+}
+
 contract UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungibleToken.sol
+++ b/tests/src/eth/api/UniqueRefungibleToken.sol
@@ -22,12 +22,6 @@
 	);
 }
 
-// Selector: 79cc6790
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	// Selector: burnFrom(address,uint256) 79cc6790
-	function burnFrom(address from, uint256 amount) external returns (bool);
-}
-
 // Selector: 942e8b22
 interface ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
@@ -65,6 +59,15 @@
 		returns (uint256);
 }
 
+// Selector: ab8deb37
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	// Selector: burnFrom(address,uint256) 79cc6790
+	function burnFrom(address from, uint256 amount) external returns (bool);
+
+	// Selector: repartition(uint256) d2418ca7
+	function repartition(uint256 amount) external returns (bool);
+}
+
 interface UniqueRefungibleToken is
 	Dummy,
 	ERC165,
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
before · tests/src/eth/reFungibleToken.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 {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';18import {createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';2021import chai from 'chai';22import chaiAsPromised from 'chai-as-promised';23chai.use(chaiAsPromised);24const expect = chai.expect;2526describe('Refungible token: Information getting', () => {27  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {28    const alice = privateKeyWrapper('//Alice');2930    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;3132    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);3334    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;3536    const address = tokenIdToAddress(collectionId, tokenId);37    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});38    const totalSupply = await contract.methods.totalSupply().call();3940    expect(totalSupply).to.equal('200');41  });4243  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {44    const alice = privateKeyWrapper('//Alice');4546    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;4748    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);4950    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;5152    const address = tokenIdToAddress(collectionId, tokenId);53    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});54    const balance = await contract.methods.balanceOf(caller).call();5556    expect(balance).to.equal('200');57  });5859  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {60    const alice = privateKeyWrapper('//Alice');6162    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;6364    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6566    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;6768    const address = tokenIdToAddress(collectionId, tokenId);69    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});70    const decimals = await contract.methods.decimals().call();7172    expect(decimals).to.equal('0');73  });74});7576describe('Refungible: Plain calls', () => {77  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {78    const alice = privateKeyWrapper('//Alice');7980    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;8182    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);8384    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;8586    const address = tokenIdToAddress(collectionId, tokenId);8788    const spender = createEthAccount(web3);8990    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});9192    {93      const result = await contract.methods.approve(spender, 100).send({from: owner});94      const events = normalizeEvents(result.events);9596      expect(events).to.be.deep.equal([97        {98          address,99          event: 'Approval',100          args: {101            owner,102            spender,103            value: '100',104          },105        },106      ]);107    }108109    {110      const allowance = await contract.methods.allowance(owner, spender).call();111      expect(+allowance).to.equal(100);112    }113  });114115  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {116    const alice = privateKeyWrapper('//Alice');117118    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;119120    const owner = createEthAccount(web3);121    await transferBalanceToEth(api, alice, owner);122123    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;124125    const spender = createEthAccount(web3);126    await transferBalanceToEth(api, alice, spender);127128    const receiver = createEthAccount(web3);129130    const address = tokenIdToAddress(collectionId, tokenId);131    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});132133    await contract.methods.approve(spender, 100).send();134135    {136      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});137      const events = normalizeEvents(result.events);138      expect(events).to.be.deep.equal([139        {140          address,141          event: 'Transfer',142          args: {143            from: owner,144            to: receiver,145            value: '49',146          },147        },148        {149          address,150          event: 'Approval',151          args: {152            owner,153            spender,154            value: '51',155          },156        },157      ]);158    }159160    {161      const balance = await contract.methods.balanceOf(receiver).call();162      expect(+balance).to.equal(49);163    }164165    {166      const balance = await contract.methods.balanceOf(owner).call();167      expect(+balance).to.equal(151);168    }169  });170171  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {172    const alice = privateKeyWrapper('//Alice');173174    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;175176    const owner = createEthAccount(web3);177    await transferBalanceToEth(api, alice, owner);178179    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;180181    const receiver = createEthAccount(web3);182    await transferBalanceToEth(api, alice, receiver);183184    const address = tokenIdToAddress(collectionId, tokenId);185    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});186187    {188      const result = await contract.methods.transfer(receiver, 50).send({from: owner});189      const events = normalizeEvents(result.events);190      expect(events).to.be.deep.equal([191        {192          address,193          event: 'Transfer',194          args: {195            from: owner,196            to: receiver,197            value: '50',198          },199        },200      ]);201    }202203    {204      const balance = await contract.methods.balanceOf(owner).call();205      expect(+balance).to.equal(150);206    }207208    {209      const balance = await contract.methods.balanceOf(receiver).call();210      expect(+balance).to.equal(50);211    }212  });213});214215describe('Refungible: Fees', () => {216  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {217    const alice = privateKeyWrapper('//Alice');218219    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;220221    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);222    const spender = createEthAccount(web3);223224    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;225226    const address = tokenIdToAddress(collectionId, tokenId);227    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});228229    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));230    expect(cost < BigInt(0.2 * Number(UNIQUE)));231  });232233  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {234    const alice = privateKeyWrapper('//Alice');235236    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;237238    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);239    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);240241    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;242243    const address = tokenIdToAddress(collectionId, tokenId);244    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});245246    await contract.methods.approve(spender, 100).send({from: owner});247248    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));249    expect(cost < BigInt(0.2 * Number(UNIQUE)));250  });251252  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {253    const alice = privateKeyWrapper('//Alice');254255    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;256257    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);258    const receiver = createEthAccount(web3);259260    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;261262    const address = tokenIdToAddress(collectionId, tokenId);263    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});264265    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));266    expect(cost < BigInt(0.2 * Number(UNIQUE)));267  });268});269270describe('Refungible: Substrate calls', () => {271  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {272    const alice = privateKeyWrapper('//Alice');273274    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;275276    const receiver = createEthAccount(web3);277278    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;279280    const address = tokenIdToAddress(collectionId, tokenId);281    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);282283    const events = await recordEvents(contract, async () => {284      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;285    });286287    expect(events).to.be.deep.equal([288      {289        address,290        event: 'Approval',291        args: {292          owner: subToEth(alice.address),293          spender: receiver,294          value: '100',295        },296      },297    ]);298  });299300  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {301    const alice = privateKeyWrapper('//Alice');302303    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;304    const bob = privateKeyWrapper('//Bob');305306    const receiver = createEthAccount(web3);307308    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;309    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;310311    const address = tokenIdToAddress(collectionId, tokenId);312    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);313314    const events = await recordEvents(contract, async () => {315      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;316    });317318    expect(events).to.be.deep.equal([319      {320        address,321        event: 'Transfer',322        args: {323          from: subToEth(alice.address),324          to: receiver,325          value: '51',326        },327      },328      {329        address,330        event: 'Approval',331        args: {332          owner: subToEth(alice.address),333          spender: subToEth(bob.address),334          value: '49',335        },336      },337    ]);338  });339340  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {341    const alice = privateKeyWrapper('//Alice');342343    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;344345    const receiver = createEthAccount(web3);346347    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;348349    const address = tokenIdToAddress(collectionId, tokenId);350    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);351352    const events = await recordEvents(contract, async () => {353      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;354    });355356    expect(events).to.be.deep.equal([357      {358        address,359        event: 'Transfer',360        args: {361          from: subToEth(alice.address),362          to: receiver,363          value: '51',364        },365      },366    ]);367  });368});
after · tests/src/eth/reFungibleToken.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 {approve, createCollection, createRefungibleToken, transfer, transferFrom, UNIQUE} from '../util/helpers';18import {createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, tokenIdToAddress, transferBalanceToEth} from './util/helpers';19import reFungibleTokenAbi from './reFungibleTokenAbi.json';2021import chai from 'chai';22import chaiAsPromised from 'chai-as-promised';23chai.use(chaiAsPromised);24const expect = chai.expect;2526describe('Refungible token: Information getting', () => {27  itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {28    const alice = privateKeyWrapper('//Alice');2930    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;3132    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);3334    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;3536    const address = tokenIdToAddress(collectionId, tokenId);37    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});38    const totalSupply = await contract.methods.totalSupply().call();3940    expect(totalSupply).to.equal('200');41  });4243  itWeb3('balanceOf', async ({api, web3, privateKeyWrapper}) => {44    const alice = privateKeyWrapper('//Alice');4546    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;4748    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);4950    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;5152    const address = tokenIdToAddress(collectionId, tokenId);53    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});54    const balance = await contract.methods.balanceOf(caller).call();5556    expect(balance).to.equal('200');57  });5859  itWeb3('decimals', async ({api, web3, privateKeyWrapper}) => {60    const alice = privateKeyWrapper('//Alice');6162    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;6364    const caller = await createEthAccountWithBalance(api, web3, privateKeyWrapper);6566    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: caller})).itemId;6768    const address = tokenIdToAddress(collectionId, tokenId);69    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: caller, ...GAS_ARGS});70    const decimals = await contract.methods.decimals().call();7172    expect(decimals).to.equal('0');73  });74});7576describe('Refungible: Plain calls', () => {77  itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {78    const alice = privateKeyWrapper('//Alice');7980    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;8182    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);8384    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;8586    const address = tokenIdToAddress(collectionId, tokenId);8788    const spender = createEthAccount(web3);8990    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});9192    {93      const result = await contract.methods.approve(spender, 100).send({from: owner});94      const events = normalizeEvents(result.events);9596      expect(events).to.be.deep.equal([97        {98          address,99          event: 'Approval',100          args: {101            owner,102            spender,103            value: '100',104          },105        },106      ]);107    }108109    {110      const allowance = await contract.methods.allowance(owner, spender).call();111      expect(+allowance).to.equal(100);112    }113  });114115  itWeb3('Can perform transferFrom()', async ({web3, api, privateKeyWrapper}) => {116    const alice = privateKeyWrapper('//Alice');117118    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;119120    const owner = createEthAccount(web3);121    await transferBalanceToEth(api, alice, owner);122123    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;124125    const spender = createEthAccount(web3);126    await transferBalanceToEth(api, alice, spender);127128    const receiver = createEthAccount(web3);129130    const address = tokenIdToAddress(collectionId, tokenId);131    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});132133    await contract.methods.approve(spender, 100).send();134135    {136      const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender});137      const events = normalizeEvents(result.events);138      expect(events).to.be.deep.equal([139        {140          address,141          event: 'Transfer',142          args: {143            from: owner,144            to: receiver,145            value: '49',146          },147        },148        {149          address,150          event: 'Approval',151          args: {152            owner,153            spender,154            value: '51',155          },156        },157      ]);158    }159160    {161      const balance = await contract.methods.balanceOf(receiver).call();162      expect(+balance).to.equal(49);163    }164165    {166      const balance = await contract.methods.balanceOf(owner).call();167      expect(+balance).to.equal(151);168    }169  });170171  itWeb3('Can perform transfer()', async ({web3, api, privateKeyWrapper}) => {172    const alice = privateKeyWrapper('//Alice');173174    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;175176    const owner = createEthAccount(web3);177    await transferBalanceToEth(api, alice, owner);178179    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;180181    const receiver = createEthAccount(web3);182    await transferBalanceToEth(api, alice, receiver);183184    const address = tokenIdToAddress(collectionId, tokenId);185    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});186187    {188      const result = await contract.methods.transfer(receiver, 50).send({from: owner});189      const events = normalizeEvents(result.events);190      expect(events).to.be.deep.equal([191        {192          address,193          event: 'Transfer',194          args: {195            from: owner,196            to: receiver,197            value: '50',198          },199        },200      ]);201    }202203    {204      const balance = await contract.methods.balanceOf(owner).call();205      expect(+balance).to.equal(150);206    }207208    {209      const balance = await contract.methods.balanceOf(receiver).call();210      expect(+balance).to.equal(50);211    }212  });213214  itWeb3('Can perform repartition()', async ({web3, api, privateKeyWrapper}) => {215    const alice = privateKeyWrapper('//Alice');216217    const collectionId = (await createCollection(api, alice, {name: 'token name', mode: {type: 'ReFungible'}})).collectionId;218219    const owner = createEthAccount(web3);220    await transferBalanceToEth(api, alice, owner);221222    const receiver = createEthAccount(web3);223    await transferBalanceToEth(api, alice, receiver);224225    const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n, {Ethereum: owner})).itemId;226227    const address = tokenIdToAddress(collectionId, tokenId);228    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});229230    await contract.methods.repartition(200).send({from: owner});231    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200);232    await contract.methods.transfer(receiver, 110).send({from: owner});233    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(90);234    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(110);235    236    await expect(contract.methods.repartition(80).send({from: owner})).to.eventually.be.rejected;237238    await contract.methods.transfer(receiver, 90).send({from: owner});239    expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(0);240    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(200);241242    await contract.methods.repartition(150).send({from: receiver});243    await expect(contract.methods.transfer(owner, 160).send({from: receiver})).to.eventually.be.rejected;244    expect(+await contract.methods.balanceOf(receiver).call()).to.be.equal(150);245  });246});247248describe('Refungible: Fees', () => {249  itWeb3('approve() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {250    const alice = privateKeyWrapper('//Alice');251252    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;253254    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);255    const spender = createEthAccount(web3);256257    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;258259    const address = tokenIdToAddress(collectionId, tokenId);260    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});261262    const cost = await recordEthFee(api, owner, () => contract.methods.approve(spender, 100).send({from: owner}));263    expect(cost < BigInt(0.2 * Number(UNIQUE)));264  });265266  itWeb3('transferFrom() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {267    const alice = privateKeyWrapper('//Alice');268269    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;270271    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);272    const spender = await createEthAccountWithBalance(api, web3, privateKeyWrapper);273274    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;275276    const address = tokenIdToAddress(collectionId, tokenId);277    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});278279    await contract.methods.approve(spender, 100).send({from: owner});280281    const cost = await recordEthFee(api, spender, () => contract.methods.transferFrom(owner, spender, 100).send({from: spender}));282    expect(cost < BigInt(0.2 * Number(UNIQUE)));283  });284285  itWeb3('transfer() call fee is less than 0.2UNQ', async ({web3, api, privateKeyWrapper}) => {286    const alice = privateKeyWrapper('//Alice');287288    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;289290    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);291    const receiver = createEthAccount(web3);292293    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n, {Ethereum: owner})).itemId;294295    const address = tokenIdToAddress(collectionId, tokenId);296    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address, {from: owner, ...GAS_ARGS});297298    const cost = await recordEthFee(api, owner, () => contract.methods.transfer(receiver, 100).send({from: owner}));299    expect(cost < BigInt(0.2 * Number(UNIQUE)));300  });301});302303describe('Refungible: Substrate calls', () => {304  itWeb3('Events emitted for approve()', async ({web3, api, privateKeyWrapper}) => {305    const alice = privateKeyWrapper('//Alice');306307    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;308309    const receiver = createEthAccount(web3);310311    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;312313    const address = tokenIdToAddress(collectionId, tokenId);314    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);315316    const events = await recordEvents(contract, async () => {317      expect(await approve(api, collectionId, tokenId, alice, {Ethereum: receiver}, 100n)).to.be.true;318    });319320    expect(events).to.be.deep.equal([321      {322        address,323        event: 'Approval',324        args: {325          owner: subToEth(alice.address),326          spender: receiver,327          value: '100',328        },329      },330    ]);331  });332333  itWeb3('Events emitted for transferFrom()', async ({web3, api, privateKeyWrapper}) => {334    const alice = privateKeyWrapper('//Alice');335336    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;337    const bob = privateKeyWrapper('//Bob');338339    const receiver = createEthAccount(web3);340341    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;342    expect(await approve(api, collectionId, tokenId, alice, bob.address, 100n)).to.be.true;343344    const address = tokenIdToAddress(collectionId, tokenId);345    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);346347    const events = await recordEvents(contract, async () => {348      expect(await transferFrom(api, collectionId, tokenId, bob, alice, {Ethereum: receiver},  51n)).to.be.true;349    });350351    expect(events).to.be.deep.equal([352      {353        address,354        event: 'Transfer',355        args: {356          from: subToEth(alice.address),357          to: receiver,358          value: '51',359        },360      },361      {362        address,363        event: 'Approval',364        args: {365          owner: subToEth(alice.address),366          spender: subToEth(bob.address),367          value: '49',368        },369      },370    ]);371  });372373  itWeb3('Events emitted for transfer()', async ({web3, api, privateKeyWrapper}) => {374    const alice = privateKeyWrapper('//Alice');375376    const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;377378    const receiver = createEthAccount(web3);379380    const tokenId = (await createRefungibleToken(api, alice, collectionId, 200n)).itemId;381382    const address = tokenIdToAddress(collectionId, tokenId);383    const contract = new web3.eth.Contract(reFungibleTokenAbi as any, address);384385    const events = await recordEvents(contract, async () => {386      expect(await transfer(api, collectionId, tokenId, alice, {Ethereum: receiver},  51n)).to.be.true;387    });388389    expect(events).to.be.deep.equal([390      {391        address,392        event: 'Transfer',393        args: {394          from: subToEth(alice.address),395          to: receiver,396          value: '51',397        },398      },399    ]);400  });401});
modifiedtests/src/eth/reFungibleTokenAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/reFungibleTokenAbi.json
+++ b/tests/src/eth/reFungibleTokenAbi.json
@@ -104,6 +104,15 @@
   },
   {
     "inputs": [
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "repartition",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
       { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
     ],
     "name": "supportsInterface",