--- a/pallets/common/src/eth.rs +++ b/pallets/common/src/eth.rs @@ -631,12 +631,3 @@ } } } - -/// Token minting parameters -#[derive(AbiCoder, Default, Debug)] -pub struct MintTokenData { - /// Minted token owner - pub owner: CrossAddress, - /// Minted token properties - pub properties: Vec, -} --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -26,7 +26,7 @@ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, }; -use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*}; +use evm_coder::{abi::AbiType, AbiCoder, ToLog, generate_stubgen, solidity_interface, types::*}; use frame_support::BoundedVec; use up_data_structs::{ TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey, @@ -64,6 +64,15 @@ }, } +/// Token minting parameters +#[derive(AbiCoder, Default, Debug)] +pub struct MintTokenData { + /// Minted token owner + pub owner: eth::CrossAddress, + /// Minted token properties + pub properties: Vec, +} + frontier_contract! { macro_rules! NonfungibleHandle_result {...} impl Contract for NonfungibleHandle {...} @@ -984,14 +993,14 @@ /// @notice Function to mint a token. /// @param data Array of pairs of token owner and token's properties for minted token #[weight(>::create_multiple_items(data.len() as u32) + >::set_token_properties(data.len() as u32))] - fn mint_bulk_cross(&mut self, caller: Caller, data: Vec) -> Result { + fn mint_bulk_cross(&mut self, caller: Caller, data: Vec) -> Result { let caller = T::CrossAccountId::from_eth(caller); let budget = self .recorder .weight_calls_budget(>::find_parent()); let mut create_nft_data = Vec::with_capacity(data.len()); - for eth::MintTokenData { owner, properties } in data { + for MintTokenData { owner, properties } in data { let owner = owner.into_sub_cross_account::()?; create_nft_data.push(CreateItemData:: { properties: properties --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -1055,8 +1055,11 @@ string uri; } +/// Token minting parameters struct MintTokenData { + /// Minted token owner CrossAddress owner; + /// Minted token properties Property[] properties; } --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -26,7 +26,7 @@ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, }; -use evm_coder::{abi::AbiType, ToLog, generate_stubgen, solidity_interface, types::*}; +use evm_coder::{abi::AbiType, AbiCoder, ToLog, generate_stubgen, solidity_interface, types::*}; use frame_support::{BoundedBTreeMap, BoundedVec}; use pallet_common::{ CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, @@ -71,6 +71,24 @@ }, } +/// Token minting parameters +#[derive(AbiCoder, Default, Debug)] +pub struct OwnerPieces { + /// Minted token owner + pub owner: eth::CrossAddress, + /// Number of token pieces + pub pieces: u128, +} + +/// Token minting parameters +#[derive(AbiCoder, Default, Debug)] +pub struct MintTokenData { + /// Minted token owner and number of pieces + pub owners: Vec, + /// Minted token properties + pub properties: Vec, +} + /// @title A contract that allows to set and delete token properties and change token property permissions. #[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))] impl RefungibleHandle { @@ -1027,7 +1045,7 @@ fn mint_bulk_cross( &mut self, caller: Caller, - token_properties: Vec, + token_properties: Vec, ) -> Result { let caller = T::CrossAccountId::from_eth(caller); let budget = self @@ -1035,11 +1053,11 @@ .weight_calls_budget(>::find_parent()); let mut create_rft_data = Vec::with_capacity(token_properties.len()); - for eth::MintTokenData { owner, properties } in token_properties { - let owner = owner.into_sub_cross_account::()?; - let users: BoundedBTreeMap<_, _, _> = [(owner, 1)] + for MintTokenData { owners, properties } in token_properties { + let users: BoundedBTreeMap<_, _, _> = owners .into_iter() - .collect::>() + .map(|data| Ok((data.owner.into_sub_cross_account::()?, data.pieces))) + .collect::>>()? .try_into() .map_err(|_| "too many users")?; create_rft_data.push(CreateItemData:: { --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -800,7 +800,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x3e828d60 +/// @dev the ERC-165 identifier for this interface is 0x4abaabdb 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, @@ -988,8 +988,8 @@ /// @notice Function to mint a token. /// @param tokenProperties Properties of minted token - /// @dev EVM selector for this function is: 0xab427b0c, - /// or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[]) + /// @dev EVM selector for this function is: 0xdf7a5db7, + /// or in textual repr: mintBulkCross((((address,uint256),uint128)[],(string,bytes)[])[]) function mintBulkCross(MintTokenData[] memory tokenProperties) public returns (bool) { require(false, stub_error); tokenProperties; @@ -1056,11 +1056,22 @@ string uri; } +/// Token minting parameters struct MintTokenData { - CrossAddress owner; + /// Minted token owner and number of pieces + OwnerPieces[] owners; + /// Minted token properties Property[] properties; } +/// Token minting parameters +struct OwnerPieces { + /// Minted token owner + CrossAddress owner; + /// Number of token pieces + uint128 pieces; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/tests/src/eth/abi/reFungible.json +++ b/tests/src/eth/abi/reFungible.json @@ -453,12 +453,28 @@ "components": [ { "components": [ - { "internalType": "address", "name": "eth", "type": "address" }, - { "internalType": "uint256", "name": "sub", "type": "uint256" } + { + "components": [ + { + "internalType": "address", + "name": "eth", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sub", + "type": "uint256" + } + ], + "internalType": "struct CrossAddress", + "name": "owner", + "type": "tuple" + }, + { "internalType": "uint128", "name": "pieces", "type": "uint128" } ], - "internalType": "struct CrossAddress", - "name": "owner", - "type": "tuple" + "internalType": "struct OwnerPieces[]", + "name": "owners", + "type": "tuple[]" }, { "components": [ --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -711,8 +711,11 @@ string uri; } +/// Token minting parameters struct MintTokenData { + /// Minted token owner CrossAddress owner; + /// Minted token properties Property[] properties; } --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -551,7 +551,7 @@ } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x3e828d60 +/// @dev the ERC-165 identifier for this interface is 0x4abaabdb 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, @@ -670,8 +670,8 @@ /// @notice Function to mint a token. /// @param tokenProperties Properties of minted token - /// @dev EVM selector for this function is: 0xab427b0c, - /// or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[]) + /// @dev EVM selector for this function is: 0xdf7a5db7, + /// or in textual repr: mintBulkCross((((address,uint256),uint128)[],(string,bytes)[])[]) function mintBulkCross(MintTokenData[] memory tokenProperties) external returns (bool); // /// @notice Function to mint multiple tokens with the given tokenUris. @@ -712,11 +712,22 @@ string uri; } +/// Token minting parameters struct MintTokenData { - CrossAddress owner; + /// Minted token owner and number of pieces + OwnerPieces[] owners; + /// Minted token properties Property[] properties; } +/// Token minting parameters +struct OwnerPieces { + /// Minted token owner + CrossAddress owner; + /// Number of token pieces + uint128 pieces; +} + /// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// @dev the ERC-165 identifier for this interface is 0x780e9d63 --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -216,7 +216,7 @@ name: 'A', description: 'B', tokenPrefix: 'C', - collectionMode: 'rft', + collectionMode: 'nft', adminList: [callerCross], tokenPropertyPermissions: [ {key: 'key_0_0', permissions}, --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -131,6 +131,8 @@ const callerCross = helper.ethCrossAccount.fromAddress(caller); const receiver = helper.eth.createAccount(); const receiverCross = helper.ethCrossAccount.fromAddress(receiver); + const receiver2 = helper.eth.createAccount(); + const receiver2Cross = helper.ethCrossAccount.fromAddress(receiver2); const permissions = [ {code: TokenPermissionField.Mutable, value: true}, @@ -157,26 +159,41 @@ }, ).send(); - const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); { const nextTokenId = await contract.methods.nextTokenId().call(); expect(nextTokenId).to.be.equal('1'); const result = await contract.methods.mintBulkCross([ { - owner: receiverCross, + owners: [{ + owner: receiverCross, + pieces: 1, + }], properties: [ {key: 'key_0_0', value: Buffer.from('value_0_0')}, ], }, { - owner: receiverCross, + owners: [{ + owner: receiverCross, + pieces: 2, + }], properties: [ {key: 'key_1_0', value: Buffer.from('value_1_0')}, {key: 'key_1_1', value: Buffer.from('value_1_1')}, ], }, { - owner: receiverCross, + owners: [ + { + owner: receiverCross, + pieces: 1, + }, + { + owner: receiver2Cross, + pieces: 2, + }, + ], properties: [ {key: 'key_2_0', value: Buffer.from('value_2_0')}, {key: 'key_2_1', value: Buffer.from('value_2_1')}, @@ -190,7 +207,11 @@ const event = events[i]; expect(event.address).to.equal(collectionAddress); expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000'); - expect(event.returnValues.to).to.equal(receiver); + if(i == 0 || i == 1) + expect(event.returnValues.to).to.equal(receiver); + else + expect(event.returnValues.to).to.equal('0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF'); + expect(event.returnValues.tokenId).to.equal(`${+nextTokenId + i}`); }