From b29d888786e16cec1282c357f1b3f3011c660211 Mon Sep 17 00:00:00 2001 From: PraetorP Date: Thu, 01 Dec 2022 08:22:08 +0000 Subject: [PATCH] added `mintCross` function for `UniqueExtensoins` interfaces --- --- a/Cargo.lock +++ b/Cargo.lock @@ -6085,7 +6085,7 @@ [[package]] name = "pallet-fungible" -version = "0.1.7" +version = "0.1.9" dependencies = [ "ethereum 0.14.0", "evm-coder", --- a/pallets/fungible/CHANGELOG.md +++ b/pallets/fungible/CHANGELOG.md @@ -4,6 +4,12 @@ +## [0.1.9] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC20UniqueExtensions` interface. + ## [0.1.8] - 2022-11-18 ### Added --- a/pallets/fungible/Cargo.toml +++ b/pallets/fungible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-fungible" -version = "0.1.7" +version = "0.1.9" license = "GPLv3" edition = "2021" --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -174,6 +174,19 @@ .collect::()) } + #[weight(>::create_item())] + fn mint_cross(&mut self, caller: caller, to: EthCrossAccount, amount: uint256) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + >::create_item(&self, &caller, (to, amount), &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + #[weight(>::approve())] fn approve_cross( &mut self, --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -152,10 +152,10 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple8 memory) { + function collectionSponsor() public view returns (Tuple9 memory) { require(false, stub_error); dummy; - return Tuple8(0x0000000000000000000000000000000000000000, 0); + return Tuple9(0x0000000000000000000000000000000000000000, 0); } /// Get current collection limits. @@ -522,7 +522,7 @@ bytes value; } -/// @dev the ERC-165 identifier for this interface is 0x5b7038cf +/// @dev the ERC-165 identifier for this interface is 0x7dee5997 contract ERC20UniqueExtensions is Dummy, ERC165 { /// @notice A description for the collection. /// @dev EVM selector for this function is: 0x7284e416, @@ -533,6 +533,16 @@ return ""; } + /// @dev EVM selector for this function is: 0x269e6158, + /// or in textual repr: mintCross((address,uint256),uint256) + function mintCross(EthCrossAccount memory to, uint256 amount) public returns (bool) { + require(false, stub_error); + to; + amount; + dummy = 0; + return false; + } + /// @dev EVM selector for this function is: 0x0ecd0ab0, /// or in textual repr: approveCross((address,uint256),uint256) function approveCross(EthCrossAccount memory spender, uint256 amount) public returns (bool) { @@ -577,7 +587,7 @@ /// @param amounts array of pairs of account address and amount /// @dev EVM selector for this function is: 0x1acf2d55, /// or in textual repr: mintBulk((address,uint256)[]) - function mintBulk(Tuple8[] memory amounts) public returns (bool) { + function mintBulk(Tuple9[] memory amounts) public returns (bool) { require(false, stub_error); amounts; dummy = 0; @@ -611,7 +621,7 @@ } /// @dev anonymous struct -struct Tuple8 { +struct Tuple9 { address field_0; uint256 field_1; } --- a/pallets/nonfungible/CHANGELOG.md +++ b/pallets/nonfungible/CHANGELOG.md @@ -4,7 +4,7 @@ -## [0.1.11] - 2022-12-16 +## [0.1.12] - 2022-12-16 ### Added @@ -14,6 +14,12 @@ - Hide `setTokenPropertyPermission` function in `TokenProperties` interface. +## [0.1.11] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC721UniqueExtensions` interface. + ## [0.1.10] - 2022-11-18 ### Added --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -1069,6 +1069,58 @@ .map_err(dispatch_to_evm::)?; Ok(true) } + + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + #[weight(>::create_item())] + fn mint_cross( + &mut self, + caller: caller, + to: EthCrossAccount, + properties: Vec, + ) -> Result { + let token_id = >::get(self.id) + .checked_add(1) + .ok_or("item id overflow")?; + + let to = to.into_sub_cross_account::()?; + + let properties = properties + .into_iter() + .map(|PropertyStruct { key, value }| { + let key = >::from(key) + .try_into() + .map_err(|_| "key too large")?; + + let value = value.0.try_into().map_err(|_| "value too large")?; + + Ok(Property { key, value }) + }) + .collect::>>()? + .try_into() + .map_err(|_| Error::Revert(alloc::format!("too many properties")))?; + + let caller = T::CrossAccountId::from_eth(caller); + + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::create_item( + self, + &caller, + CreateItemData:: { + properties, + owner: to, + }, + &budget, + ) + .map_err(dispatch_to_evm::)?; + + Ok(token_id.into()) + } } #[solidity_interface( --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -290,10 +290,10 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple30 memory) { + function collectionSponsor() public view returns (Tuple32 memory) { require(false, stub_error); dummy; - return Tuple30(0x0000000000000000000000000000000000000000, 0); + return Tuple32(0x0000000000000000000000000000000000000000, 0); } /// Get current collection limits. @@ -655,7 +655,7 @@ } /// @dev anonymous struct -struct Tuple30 { +struct Tuple32 { address field_0; uint256 field_1; } @@ -804,7 +804,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xb74c26b7 +/// @dev the ERC-165 identifier for this interface is 0x0e48fdb4 contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -961,6 +961,7 @@ dummy; return 0; } + // /// @notice Function to mint multiple tokens. // /// @dev `tokenIds` should be an array of consecutive numbers and first number // /// should be obtained with `nextTokenId` method @@ -991,6 +992,19 @@ // return false; // } + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(EthCrossAccount memory to, Property[] memory properties) public returns (uint256) { + require(false, stub_error); + to; + properties; + dummy = 0; + return 0; + } } /// @dev anonymous struct --- a/pallets/refungible/CHANGELOG.md +++ b/pallets/refungible/CHANGELOG.md @@ -4,7 +4,7 @@ -## [0.2.10] - 2022-12-16 +## [0.2.11] - 2022-12-16 ### Added @@ -14,6 +14,12 @@ - Hide `setTokenPropertyPermission` function in `TokenProperties` interface. +## [0.2.10] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC721UniqueExtensions` interface. + ## [0.2.9] - 2022-11-18 ### Added --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -1120,6 +1120,60 @@ Ok(true) } + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + #[weight(>::create_item())] + fn mint_cross( + &mut self, + caller: caller, + to: EthCrossAccount, + properties: Vec, + ) -> Result { + let token_id = >::get(self.id) + .checked_add(1) + .ok_or("item id overflow")?; + + let to = to.into_sub_cross_account::()?; + + let properties = properties + .into_iter() + .map(|PropertyStruct { key, value }| { + let key = >::from(key) + .try_into() + .map_err(|_| "key too large")?; + + let value = value.0.try_into().map_err(|_| "value too large")?; + + Ok(Property { key, value }) + }) + .collect::>>()? + .try_into() + .map_err(|_| Error::Revert(alloc::format!("too many properties")))?; + + let caller = T::CrossAccountId::from_eth(caller); + + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let users = [(to, 1)] + .into_iter() + .collect::>() + .try_into() + .unwrap(); + >::create_item( + self, + &caller, + CreateItemData:: { users, properties }, + &budget, + ) + .map_err(dispatch_to_evm::)?; + + Ok(token_id.into()) + } + /// Returns EVM address for refungible token /// /// @param token ID of the token --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -290,10 +290,10 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple29 memory) { + function collectionSponsor() public view returns (Tuple31 memory) { require(false, stub_error); dummy; - return Tuple29(0x0000000000000000000000000000000000000000, 0); + return Tuple31(0x0000000000000000000000000000000000000000, 0); } /// Get current collection limits. @@ -655,7 +655,7 @@ } /// @dev anonymous struct -struct Tuple29 { +struct Tuple31 { address field_0; uint256 field_1; } @@ -802,7 +802,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x12f7d6c1 +/// @dev the ERC-165 identifier for this interface is 0xabf30dc2 contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -979,6 +979,20 @@ // return false; // } + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(EthCrossAccount memory to, Property[] memory properties) public returns (uint256) { + require(false, stub_error); + to; + properties; + dummy = 0; + return 0; + } + /// Returns EVM address for refungible token /// /// @param token ID of the token --- a/tests/src/eth/abi/fungible.json +++ b/tests/src/eth/abi/fungible.json @@ -322,7 +322,7 @@ { "internalType": "address", "name": "field_0", "type": "address" }, { "internalType": "uint256", "name": "field_1", "type": "uint256" } ], - "internalType": "struct Tuple8", + "internalType": "struct Tuple9", "name": "", "type": "tuple" } @@ -408,7 +408,7 @@ { "internalType": "address", "name": "field_0", "type": "address" }, { "internalType": "uint256", "name": "field_1", "type": "uint256" } ], - "internalType": "struct Tuple8[]", + "internalType": "struct Tuple9[]", "name": "amounts", "type": "tuple[]" } @@ -419,6 +419,24 @@ "type": "function" }, { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct EthCrossAccount", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "mintCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], --- a/tests/src/eth/abi/nonFungible.json +++ b/tests/src/eth/abi/nonFungible.json @@ -352,7 +352,7 @@ { "internalType": "address", "name": "field_0", "type": "address" }, { "internalType": "uint256", "name": "field_1", "type": "uint256" } ], - "internalType": "struct Tuple30", + "internalType": "struct Tuple32", "name": "", "type": "tuple" } @@ -478,6 +478,32 @@ }, { "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct EthCrossAccount", + "name": "to", + "type": "tuple" + }, + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "mintCross", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "string", "name": "tokenUri", "type": "string" } ], --- a/tests/src/eth/abi/reFungible.json +++ b/tests/src/eth/abi/reFungible.json @@ -334,7 +334,7 @@ { "internalType": "address", "name": "field_0", "type": "address" }, { "internalType": "uint256", "name": "field_1", "type": "uint256" } ], - "internalType": "struct Tuple29", + "internalType": "struct Tuple31", "name": "", "type": "tuple" } @@ -460,6 +460,32 @@ }, { "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct EthCrossAccount", + "name": "to", + "type": "tuple" + }, + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "mintCross", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "string", "name": "tokenUri", "type": "string" } ], --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -102,7 +102,7 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple8 memory); + function collectionSponsor() external view returns (Tuple9 memory); /// Get current collection limits. /// @@ -362,13 +362,17 @@ bytes value; } -/// @dev the ERC-165 identifier for this interface is 0x5b7038cf +/// @dev the ERC-165 identifier for this interface is 0x7dee5997 interface ERC20UniqueExtensions is Dummy, ERC165 { /// @notice A description for the collection. /// @dev EVM selector for this function is: 0x7284e416, /// or in textual repr: description() function description() external view returns (string memory); + /// @dev EVM selector for this function is: 0x269e6158, + /// or in textual repr: mintCross((address,uint256),uint256) + function mintCross(EthCrossAccount memory to, uint256 amount) external returns (bool); + /// @dev EVM selector for this function is: 0x0ecd0ab0, /// or in textual repr: approveCross((address,uint256),uint256) function approveCross(EthCrossAccount memory spender, uint256 amount) external returns (bool); @@ -395,7 +399,7 @@ /// @param amounts array of pairs of account address and amount /// @dev EVM selector for this function is: 0x1acf2d55, /// or in textual repr: mintBulk((address,uint256)[]) - function mintBulk(Tuple8[] memory amounts) external returns (bool); + function mintBulk(Tuple9[] memory amounts) external returns (bool); /// @dev EVM selector for this function is: 0x2ada85ff, /// or in textual repr: transferCross((address,uint256),uint256) @@ -411,7 +415,7 @@ } /// @dev anonymous struct -struct Tuple8 { +struct Tuple9 { address field_0; uint256 field_1; } --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -198,7 +198,7 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple27 memory); + function collectionSponsor() external view returns (Tuple29 memory); /// Get current collection limits. /// @@ -553,7 +553,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xb74c26b7 +/// @dev the ERC-165 identifier for this interface is 0x0e48fdb4 interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -652,6 +652,7 @@ /// @dev EVM selector for this function is: 0x75794a3c, /// or in textual repr: nextTokenId() function nextTokenId() external view returns (uint256); + // /// @notice Function to mint multiple tokens. // /// @dev `tokenIds` should be an array of consecutive numbers and first number // /// should be obtained with `nextTokenId` method @@ -670,6 +671,13 @@ // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) // function mintBulkWithTokenURI(address to, Tuple13[] memory tokens) external returns (bool); + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(EthCrossAccount memory to, Property[] memory properties) external returns (uint256); } /// @dev anonymous struct --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -198,7 +198,7 @@ /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple26 memory); + function collectionSponsor() external view returns (Tuple28 memory); /// Get current collection limits. /// @@ -551,7 +551,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x12f7d6c1 +/// @dev the ERC-165 identifier for this interface is 0xabf30dc2 interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -663,6 +663,14 @@ // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) // function mintBulkWithTokenURI(address to, Tuple12[] memory tokens) external returns (bool); + /// @notice Function to mint token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(EthCrossAccount memory to, Property[] memory properties) external returns (uint256); + /// Returns EVM address for refungible token /// /// @param token ID of the token --- a/tests/src/eth/fungible.test.ts +++ b/tests/src/eth/fungible.test.ts @@ -78,6 +78,25 @@ expect(event.returnValues.to).to.equal(receiver); expect(event.returnValues.value).to.equal('100'); }); + + + itEth('Can perform mintCross()', async ({helper}) => { + const receiverCross = helper.ethCrossAccount.fromKeyringPair(owner); + const ethOwner = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.ft.mintCollection(alice); + await collection.addAdmin(alice, {Ethereum: ethOwner}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner); + + const result = await contract.methods.mintCross(receiverCross, 100).send(); + + const event = result.events.Transfer; + expect(event.address).to.equal(collectionAddress); + expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.equal(helper.address.substrateToEth(owner.address)); + expect(event.returnValues.value).to.equal('100'); + }); itEth('Can perform mintBulk()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -17,6 +17,8 @@ import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util'; import {IKeyringPair} from '@polkadot/types/types'; import {Contract} from 'web3-eth-contract'; +import exp from 'constants'; +import {ITokenPropertyPermission} from '../util/playgrounds/types'; describe('NFT: Information getting', () => { @@ -173,7 +175,45 @@ // const tokenUri = await contract.methods.tokenURI(nextTokenId).call(); // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`); }); + + itEth('Can perform mintCross()', async ({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob); + const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); + const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true, + collectionAdmin: true, + mutable: true}}; }); + + + const collection = await helper.nft.mintCollection(minter, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: permissions, + }); + await collection.addAdmin(minter, {Ethereum: caller}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true); + let expectedTokenId = await contract.methods.nextTokenId().call(); + let result = await contract.methods.mintCross(receiverCross, []).send(); + let tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal(expectedTokenId); + + const event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + expectedTokenId = await contract.methods.nextTokenId().call(); + result = await contract.methods.mintCross(receiverCross, properties).send(); + tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal(expectedTokenId); + + expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); + }); + //TODO: CORE-302 add eth methods itEth.skip('Can perform mintBulk()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -17,6 +17,7 @@ import {Pallets, requirePalletsOrSkip} from '../util'; import {expect, itEth, usingEthPlaygrounds} from './util'; import {IKeyringPair} from '@polkadot/types/types'; +import { ITokenPropertyPermission } from '../util/playgrounds/types'; describe('Refungible: Information getting', () => { let donor: IKeyringPair; @@ -135,6 +136,44 @@ expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); }); + + itEth('Can perform mintCross()', async ({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob); + const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); + const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true, + collectionAdmin: true, + mutable: true}}; }); + + + const collection = await helper.rft.mintCollection(minter, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: permissions, + }); + await collection.addAdmin(minter, {Ethereum: caller}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller, true); + let expectedTokenId = await contract.methods.nextTokenId().call(); + let result = await contract.methods.mintCross(receiverCross, []).send(); + let tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal(expectedTokenId); + + const event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + expectedTokenId = await contract.methods.nextTokenId().call(); + result = await contract.methods.mintCross(receiverCross, properties).send(); + tokenId = result.events.Transfer.returnValues.tokenId; + + expect(tokenId).to.be.equal(expectedTokenId); + + expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); + }); itEth.skip('Can perform mintBulk()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); -- gitstuff