difftreelog
feature/mint-for-fungible-token
in: master
5 files changed
pallets/fungible/src/erc.rsdiffbeforeafterboth129 }129 }130}130}131132#[solidity_interface(name = "ERC20Mintable")]133impl<T: Config> FungibleHandle<T> {134 #[weight(<SelfWeightOf<T>>::create_item())]135 fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {136 let caller = T::CrossAccountId::from_eth(caller);137 let to = T::CrossAccountId::from_eth(to);138 let amount = amount.try_into().map_err(|_| "amount overflow")?;139 let budget = self140 .recorder141 .weight_calls_budget(<StructureWeight<T>>::find_parent());142 <Pallet<T>>::create_item(&self, &caller, (to, amount), &budget)143 .map_err(dispatch_to_evm::<T>)?;144 Ok(true)145 }146}131147132#[solidity_interface(name = ERC20UniqueExtensions)]148#[solidity_interface(name = "ERC20UniqueExtensions")]133impl<T: Config> FungibleHandle<T> {149impl<T: Config> FungibleHandle<T> {134 #[weight(<SelfWeightOf<T>>::burn_from())]150 #[weight(<SelfWeightOf<T>>::burn_from())]135 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {151 fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {145 Ok(true)161 Ok(true)146 }162 }163164 #[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]165 fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {166 let caller = T::CrossAccountId::from_eth(caller);167 let budget = self168 .recorder169 .weight_calls_budget(<StructureWeight<T>>::find_parent());170 let amounts = amounts171 .into_iter()172 .map(|(to, amount)| Ok((T::CrossAccountId::from_eth(to), amount.try_into().map_err(|_| "amount overflow")?)))173 .collect::<Result<_>>()?;174175 <Pallet<T>>::create_multiple_items(&self, &caller, amounts, &budget)176 .map_err(dispatch_to_evm::<T>)?;177 Ok(true)178 }147}179}148180149#[solidity_interface(181#[solidity_interface(150 name = UniqueFungible,182 name = UniqueFungible,151 is(183 is(152 ERC20,184 ERC20,185 ERC20Mintable,153 ERC20UniqueExtensions,186 ERC20UniqueExtensions,154 Collection(common_mut, CollectionHandle<T>),187 Collection(common_mut, CollectionHandle<T>),155 )188 )pallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 address field_0;9 uint256 field_1;10}5116/// @dev common stubs holder12// Common stubs holder7contract Dummy {13contract Dummy {8 uint8 dummy;14 uint8 dummy;9 string stub_error = "this contract is implemented in native";15 string stub_error = "this contract is implemented in native";21 }27 }22}28}232924/// @title A contract that allows you to work with collections.30// Inline25/// @dev the ERC-165 identifier for this interface is 0xe54be64031contract ERC20Events {32 event Transfer(address indexed from, address indexed to, uint256 value);33 event Approval(34 address indexed owner,35 address indexed spender,36 uint256 value37 );38}3940// Selector: 40c10f1941contract ERC20Mintable is Dummy, ERC165 {42 // Selector: mint(address,uint256) 40c10f1943 function mint(address to, uint256 amount) public returns (bool) {44 require(false, stub_error);45 to;46 amount;47 dummy = 0;48 return false;49 }50}5152// Selector: 63034ac553contract ERC20UniqueExtensions is Dummy, ERC165 {54 // Selector: burnFrom(address,uint256) 79cc679055 function burnFrom(address from, uint256 amount) public returns (bool) {56 require(false, stub_error);57 from;58 amount;59 dummy = 0;60 return false;61 }6263 // Selector: mintBulk((address,uint256)[]) 1acf2d5564 function mintBulk(Tuple0[] memory amounts) public returns (bool) {65 require(false, stub_error);66 amounts;67 dummy = 0;68 return false;69 }70}7172// Selector: 6cf113cd26contract Collection is Dummy, ERC165 {73contract Collection is Dummy, ERC165 {27 /// Set collection property.74 /// Set collection property.28 ///75 ///476 Dummy,523 Dummy,477 ERC165,524 ERC165,478 ERC20,525 ERC20,526 ERC20Mintable,479 ERC20UniqueExtensions,527 ERC20UniqueExtensions,480 Collection528 Collection481{}529{}tests/src/eth/api/UniqueFungible.soldiffbeforeafterboth334pragma solidity >=0.8.0 <0.9.0;4pragma solidity >=0.8.0 <0.9.0;56// Anonymous struct7struct Tuple0 {8 address field_0;9 uint256 field_1;10}5116/// @dev common stubs holder12// Common stubs holder7interface Dummy {13interface Dummy {8149}15}12 function supportsInterface(bytes4 interfaceID) external view returns (bool);18 function supportsInterface(bytes4 interfaceID) external view returns (bool);13}19}142015/// @title A contract that allows you to work with collections.21// Inline16/// @dev the ERC-165 identifier for this interface is 0xe54be64022interface ERC20Events {23 event Transfer(address indexed from, address indexed to, uint256 value);24 event Approval(25 address indexed owner,26 address indexed spender,27 uint256 value28 );29}3031// Selector: 40c10f1932interface ERC20Mintable is Dummy, ERC165 {33 // Selector: mint(address,uint256) 40c10f1934 function mint(address to, uint256 amount) external returns (bool);35}3637// Selector: 63034ac538interface ERC20UniqueExtensions is Dummy, ERC165 {39 // Selector: burnFrom(address,uint256) 79cc679040 function burnFrom(address from, uint256 amount) external returns (bool);4142 // Selector: mintBulk((address,uint256)[]) 1acf2d5543 function mintBulk(Tuple0[] memory amounts) external returns (bool);44}4546// Selector: 6cf113cd17interface Collection is Dummy, ERC165 {47interface Collection is Dummy, ERC165 {18 /// Set collection property.48 /// Set collection property.19 ///49 ///208 /// or in textual repr: uniqueCollectionType()238 /// or in textual repr: uniqueCollectionType()209 function uniqueCollectionType() external returns (string memory);239 function uniqueCollectionType() external returns (string memory);210211 /// Changes collection owner to another account212 ///213 /// @dev Owner can be changed only by current owner214 /// @param newOwner new owner account215 /// @dev EVM selector for this function is: 0x13af4035,216 /// or in textual repr: setOwner(address)217 function setOwner(address newOwner) external;218219 /// Changes collection owner to another substrate account220 ///221 /// @dev Owner can be changed only by current owner222 /// @param newOwner new owner substrate account223 /// @dev EVM selector for this function is: 0xb212138f,224 /// or in textual repr: setOwnerSubstrate(uint256)225 function setOwnerSubstrate(uint256 newOwner) external;226}240}227228/// @dev anonymous struct229struct Tuple6 {230 address field_0;231 uint256 field_1;232}233241234/// @dev the ERC-165 identifier for this interface is 0x79cc6790242/// @dev the ERC-165 identifier for this interface is 0x79cc6790235interface ERC20UniqueExtensions is Dummy, ERC165 {243interface ERC20UniqueExtensions is Dummy, ERC165 {298 Dummy,306 Dummy,299 ERC165,307 ERC165,300 ERC20,308 ERC20,309 ERC20Mintable,301 ERC20UniqueExtensions,310 ERC20UniqueExtensions,302 Collection311 Collection303{}312{}tests/src/eth/fungible.test.tsdiffbeforeafterboth14// You should have received a copy of the GNU General Public License14// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.161617import {approveExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';17import {approveExpectSuccess, createCollection, createCollectionExpectSuccess, createFungibleItemExpectSuccess, transferExpectSuccess, transferFromExpectSuccess, UNIQUE} from '../util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';18import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, evmCollection, GAS_ARGS, itWeb3, normalizeEvents, recordEthFee, recordEvents, subToEth, transferBalanceToEth} from './util/helpers';19import fungibleAbi from './fungibleAbi.json';19import fungibleAbi from './fungibleAbi.json';20import {expect} from 'chai';20import {expect} from 'chai';21import {submitTransactionAsync} from '../substrate/substrate-api';212222describe('Fungible: Information getting', () => {23describe('Fungible: Information getting', () => {23 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {24 itWeb3('totalSupply', async ({api, web3, privateKeyWrapper}) => {58});59});596060describe('Fungible: Plain calls', () => {61describe('Fungible: Plain calls', () => {62 itWeb3('Can perform mint()', async ({web3, api, privateKeyWrapper}) => {63 const alice = privateKeyWrapper('//Alice');64 const collection = await createCollection(api, alice, {65 name: 'token name',66 mode: {type: 'Fungible', decimalPoints: 0},67 });6869 const receiver = createEthAccount(web3);7071 const collectionIdAddress = collectionIdToAddress(collection.collectionId);72 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);73 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});74 await submitTransactionAsync(alice, changeAdminTx);7576 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});77 const result = await collectionContract.methods.mint(receiver, 100).send();78 const events = normalizeEvents(result.events);79 80 expect(events).to.be.deep.equal([81 {82 address: collectionIdAddress,83 event: 'Transfer',84 args: {85 from: '0x0000000000000000000000000000000000000000',86 to: receiver,87 value: '100',88 },89 },90 ]);91 });9293 itWeb3('Can perform mintBulk()', async ({web3, api, privateKeyWrapper}) => {94 const alice = privateKeyWrapper('//Alice');95 const collection = await createCollection(api, alice, {96 name: 'token name',97 mode: {type: 'Fungible', decimalPoints: 0},98 });99100 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);101 const receiver1 = createEthAccount(web3);102 const receiver2 = createEthAccount(web3);103 const receiver3 = createEthAccount(web3);104105 const collectionIdAddress = collectionIdToAddress(collection.collectionId);106 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});107 await submitTransactionAsync(alice, changeAdminTx);108109 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});110 const result = await collectionContract.methods.mintBulk([111 [receiver1, 10],112 [receiver2, 20],113 [receiver3, 30],114 ]).call();115 console.log(result);116 const events = normalizeEvents(result.events);117118 expect(events).to.be.deep.equal([119 {120 address:collectionIdAddress,121 event: 'Transfer',122 args: {123 from: '0x0000000000000000000000000000000000000000',124 to: receiver1,125 value: '10',126 },127 },128 {129 address:collectionIdAddress,130 event: 'Transfer',131 args: {132 from: '0x0000000000000000000000000000000000000000',133 to: receiver2,134 value: '20',135 },136 },137 {138 address:collectionIdAddress,139 event: 'Transfer',140 args: {141 from: '0x0000000000000000000000000000000000000000',142 to: receiver3,143 value: '30',144 },145 },146 ]);147 });148149 itWeb3('Can perform burn()', async ({web3, api, privateKeyWrapper}) => {150 const alice = privateKeyWrapper('//Alice');151 const collection = await createCollection(api, alice, {152 name: 'token name',153 mode: {type: 'Fungible', decimalPoints: 0},154 });155156 const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);157 const changeAdminTx = api.tx.unique.addCollectionAdmin(collection.collectionId, {Ethereum: owner});158 await submitTransactionAsync(alice, changeAdminTx);159 const receiver = await createEthAccountWithBalance(api, web3, privateKeyWrapper);160161 const collectionIdAddress = collectionIdToAddress(collection.collectionId);162 const collectionContract = evmCollection(web3, owner, collectionIdAddress, {type: 'Fungible', decimalPoints: 0});163 await collectionContract.methods.mint(receiver, 100).send();164165 const result = await collectionContract.methods.burnFrom(receiver, 49).send({from: receiver});166 167 const events = normalizeEvents(result.events);168169 expect(events).to.be.deep.equal([170 {171 address: collectionIdAddress,172 event: 'Transfer',173 args: {174 from: receiver,175 to: '0x0000000000000000000000000000000000000000',176 value: '49',177 },178 },179 ]);180181 const balance = await collectionContract.methods.balanceOf(receiver).call();182 expect(balance).to.equal('51');183 });18461 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {185 itWeb3('Can perform approve()', async ({web3, api, privateKeyWrapper}) => {62 const collection = await createCollectionExpectSuccess({186 const collection = await createCollectionExpectSuccess({tests/src/eth/fungibleAbi.jsondiffbeforeafterboth150 "stateMutability": "nonpayable",150 "stateMutability": "nonpayable",151 "type": "function"151 "type": "function"152 },152 },153 {154 "inputs": [155 { "internalType": "address", "name": "to", "type": "address" },156 { "internalType": "uint256", "name": "amount", "type": "uint256" }157 ],158 "name": "mint",159 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],160 "stateMutability": "nonpayable",161 "type": "function"162 },163 {164 "inputs": [165 {166 "components": [167 { "internalType": "address", "name": "field_0", "type": "address" },168 { "internalType": "uint256", "name": "field_1", "type": "uint256" }169 ],170 "internalType": "struct Tuple0[]",171 "name": "amounts",172 "type": "tuple[]"173 }174 ],175 "name": "mintBulk",176 "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],177 "stateMutability": "nonpayable",178 "type": "function"179 },153 {180 {154 "inputs": [],181 "inputs": [],155 "name": "getCollectionSponsor",182 "name": "getCollectionSponsor",