git.delta.rocks / unique-network / refs/commits / 0c121c74a848

difftreelog

feat add a way to split RFT between multiple owners on mint

Grigoriy Simonov2023-09-22parent: #9425c0a.patch.diff
in: master

12 files changed

modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- 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<Property>,
-}
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- 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<eth::Property>,
+}
+
 frontier_contract! {
 	macro_rules! NonfungibleHandle_result {...}
 	impl<T: Config> Contract for NonfungibleHandle<T> {...}
@@ -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(<SelfWeightOf<T>>::create_multiple_items(data.len() as u32) + <SelfWeightOf<T>>::set_token_properties(data.len() as u32))]
-	fn mint_bulk_cross(&mut self, caller: Caller, data: Vec<eth::MintTokenData>) -> Result<bool> {
+	fn mint_bulk_cross(&mut self, caller: Caller, data: Vec<MintTokenData>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let budget = self
 			.recorder
 			.weight_calls_budget(<StructureWeight<T>>::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::<T>()?;
 			create_nft_data.push(CreateItemData::<T> {
 				properties: properties
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
@@ -1055,8 +1055,11 @@
 	string uri;
 }
 
+/// Token minting parameters
 struct MintTokenData {
+	/// Minted token owner
 	CrossAddress owner;
+	/// Minted token properties
 	Property[] properties;
 }
 
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- 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<OwnerPieces>,
+	/// Minted token properties
+	pub properties: Vec<eth::Property>,
+}
+
 /// @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<T: Config> RefungibleHandle<T> {
@@ -1027,7 +1045,7 @@
 	fn mint_bulk_cross(
 		&mut self,
 		caller: Caller,
-		token_properties: Vec<eth::MintTokenData>,
+		token_properties: Vec<MintTokenData>,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let budget = self
@@ -1035,11 +1053,11 @@
 			.weight_calls_budget(<StructureWeight<T>>::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::<T>()?;
-			let users: BoundedBTreeMap<_, _, _> = [(owner, 1)]
+		for MintTokenData { owners, properties } in token_properties {
+			let users: BoundedBTreeMap<_, _, _> = owners
 				.into_iter()
-				.collect::<BTreeMap<_, _>>()
+				.map(|data| Ok((data.owner.into_sub_cross_account::<T>()?, data.pieces)))
+				.collect::<Result<BTreeMap<_, _>>>()?
 				.try_into()
 				.map_err(|_| "too many users")?;
 			create_rft_data.push(CreateItemData::<T> {
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- 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
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
before · tests/src/eth/abi/reFungible.json
1[2  {3    "anonymous": false,4    "inputs": [5      {6        "indexed": true,7        "internalType": "address",8        "name": "owner",9        "type": "address"10      },11      {12        "indexed": true,13        "internalType": "address",14        "name": "approved",15        "type": "address"16      },17      {18        "indexed": true,19        "internalType": "uint256",20        "name": "tokenId",21        "type": "uint256"22      }23    ],24    "name": "Approval",25    "type": "event"26  },27  {28    "anonymous": false,29    "inputs": [30      {31        "indexed": true,32        "internalType": "address",33        "name": "owner",34        "type": "address"35      },36      {37        "indexed": true,38        "internalType": "address",39        "name": "operator",40        "type": "address"41      },42      {43        "indexed": false,44        "internalType": "bool",45        "name": "approved",46        "type": "bool"47      }48    ],49    "name": "ApprovalForAll",50    "type": "event"51  },52  {53    "anonymous": false,54    "inputs": [55      {56        "indexed": true,57        "internalType": "uint256",58        "name": "tokenId",59        "type": "uint256"60      }61    ],62    "name": "TokenChanged",63    "type": "event"64  },65  {66    "anonymous": false,67    "inputs": [68      {69        "indexed": true,70        "internalType": "address",71        "name": "from",72        "type": "address"73      },74      {75        "indexed": true,76        "internalType": "address",77        "name": "to",78        "type": "address"79      },80      {81        "indexed": true,82        "internalType": "uint256",83        "name": "tokenId",84        "type": "uint256"85      }86    ],87    "name": "Transfer",88    "type": "event"89  },90  {91    "inputs": [92      {93        "components": [94          { "internalType": "address", "name": "eth", "type": "address" },95          { "internalType": "uint256", "name": "sub", "type": "uint256" }96        ],97        "internalType": "struct CrossAddress",98        "name": "newAdmin",99        "type": "tuple"100      }101    ],102    "name": "addCollectionAdminCross",103    "outputs": [],104    "stateMutability": "nonpayable",105    "type": "function"106  },107  {108    "inputs": [109      {110        "components": [111          { "internalType": "address", "name": "eth", "type": "address" },112          { "internalType": "uint256", "name": "sub", "type": "uint256" }113        ],114        "internalType": "struct CrossAddress",115        "name": "user",116        "type": "tuple"117      }118    ],119    "name": "addToCollectionAllowListCross",120    "outputs": [],121    "stateMutability": "nonpayable",122    "type": "function"123  },124  {125    "inputs": [126      {127        "components": [128          { "internalType": "address", "name": "eth", "type": "address" },129          { "internalType": "uint256", "name": "sub", "type": "uint256" }130        ],131        "internalType": "struct CrossAddress",132        "name": "user",133        "type": "tuple"134      }135    ],136    "name": "allowlistedCross",137    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],138    "stateMutability": "view",139    "type": "function"140  },141  {142    "inputs": [143      { "internalType": "address", "name": "approved", "type": "address" },144      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }145    ],146    "name": "approve",147    "outputs": [],148    "stateMutability": "nonpayable",149    "type": "function"150  },151  {152    "inputs": [153      { "internalType": "address", "name": "owner", "type": "address" }154    ],155    "name": "balanceOf",156    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],157    "stateMutability": "view",158    "type": "function"159  },160  {161    "inputs": [162      {163        "components": [164          { "internalType": "address", "name": "eth", "type": "address" },165          { "internalType": "uint256", "name": "sub", "type": "uint256" }166        ],167        "internalType": "struct CrossAddress",168        "name": "owner",169        "type": "tuple"170      }171    ],172    "name": "balanceOfCross",173    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],174    "stateMutability": "view",175    "type": "function"176  },177  {178    "inputs": [179      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }180    ],181    "name": "burn",182    "outputs": [],183    "stateMutability": "nonpayable",184    "type": "function"185  },186  {187    "inputs": [188      {189        "components": [190          { "internalType": "address", "name": "eth", "type": "address" },191          { "internalType": "uint256", "name": "sub", "type": "uint256" }192        ],193        "internalType": "struct CrossAddress",194        "name": "from",195        "type": "tuple"196      },197      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }198    ],199    "name": "burnFromCross",200    "outputs": [],201    "stateMutability": "nonpayable",202    "type": "function"203  },204  {205    "inputs": [206      {207        "components": [208          { "internalType": "address", "name": "eth", "type": "address" },209          { "internalType": "uint256", "name": "sub", "type": "uint256" }210        ],211        "internalType": "struct CrossAddress",212        "name": "newOwner",213        "type": "tuple"214      }215    ],216    "name": "changeCollectionOwnerCross",217    "outputs": [],218    "stateMutability": "nonpayable",219    "type": "function"220  },221  {222    "inputs": [],223    "name": "collectionAdmins",224    "outputs": [225      {226        "components": [227          { "internalType": "address", "name": "eth", "type": "address" },228          { "internalType": "uint256", "name": "sub", "type": "uint256" }229        ],230        "internalType": "struct CrossAddress[]",231        "name": "",232        "type": "tuple[]"233      }234    ],235    "stateMutability": "view",236    "type": "function"237  },238  {239    "inputs": [],240    "name": "collectionHelperAddress",241    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],242    "stateMutability": "view",243    "type": "function"244  },245  {246    "inputs": [],247    "name": "collectionLimits",248    "outputs": [249      {250        "components": [251          {252            "internalType": "enum CollectionLimitField",253            "name": "field",254            "type": "uint8"255          },256          {257            "components": [258              { "internalType": "bool", "name": "status", "type": "bool" },259              { "internalType": "uint256", "name": "value", "type": "uint256" }260            ],261            "internalType": "struct OptionUint256",262            "name": "value",263            "type": "tuple"264          }265        ],266        "internalType": "struct CollectionLimit[]",267        "name": "",268        "type": "tuple[]"269      }270    ],271    "stateMutability": "view",272    "type": "function"273  },274  {275    "inputs": [],276    "name": "collectionNesting",277    "outputs": [278      {279        "components": [280          { "internalType": "bool", "name": "token_owner", "type": "bool" },281          {282            "internalType": "bool",283            "name": "collection_admin",284            "type": "bool"285          },286          {287            "internalType": "address[]",288            "name": "restricted",289            "type": "address[]"290          }291        ],292        "internalType": "struct CollectionNestingAndPermission",293        "name": "",294        "type": "tuple"295      }296    ],297    "stateMutability": "view",298    "type": "function"299  },300  {301    "inputs": [],302    "name": "collectionOwner",303    "outputs": [304      {305        "components": [306          { "internalType": "address", "name": "eth", "type": "address" },307          { "internalType": "uint256", "name": "sub", "type": "uint256" }308        ],309        "internalType": "struct CrossAddress",310        "name": "",311        "type": "tuple"312      }313    ],314    "stateMutability": "view",315    "type": "function"316  },317  {318    "inputs": [319      { "internalType": "string[]", "name": "keys", "type": "string[]" }320    ],321    "name": "collectionProperties",322    "outputs": [323      {324        "components": [325          { "internalType": "string", "name": "key", "type": "string" },326          { "internalType": "bytes", "name": "value", "type": "bytes" }327        ],328        "internalType": "struct Property[]",329        "name": "",330        "type": "tuple[]"331      }332    ],333    "stateMutability": "view",334    "type": "function"335  },336  {337    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],338    "name": "collectionProperty",339    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],340    "stateMutability": "view",341    "type": "function"342  },343  {344    "inputs": [],345    "name": "collectionSponsor",346    "outputs": [347      {348        "components": [349          { "internalType": "address", "name": "eth", "type": "address" },350          { "internalType": "uint256", "name": "sub", "type": "uint256" }351        ],352        "internalType": "struct CrossAddress",353        "name": "",354        "type": "tuple"355      }356    ],357    "stateMutability": "view",358    "type": "function"359  },360  {361    "inputs": [],362    "name": "confirmCollectionSponsorship",363    "outputs": [],364    "stateMutability": "nonpayable",365    "type": "function"366  },367  {368    "inputs": [],369    "name": "contractAddress",370    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],371    "stateMutability": "view",372    "type": "function"373  },374  {375    "inputs": [376      { "internalType": "string[]", "name": "keys", "type": "string[]" }377    ],378    "name": "deleteCollectionProperties",379    "outputs": [],380    "stateMutability": "nonpayable",381    "type": "function"382  },383  {384    "inputs": [385      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },386      { "internalType": "string[]", "name": "keys", "type": "string[]" }387    ],388    "name": "deleteProperties",389    "outputs": [],390    "stateMutability": "nonpayable",391    "type": "function"392  },393  {394    "inputs": [],395    "name": "description",396    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],397    "stateMutability": "view",398    "type": "function"399  },400  {401    "inputs": [402      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }403    ],404    "name": "getApproved",405    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],406    "stateMutability": "view",407    "type": "function"408  },409  {410    "inputs": [],411    "name": "hasCollectionPendingSponsor",412    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],413    "stateMutability": "view",414    "type": "function"415  },416  {417    "inputs": [418      { "internalType": "address", "name": "owner", "type": "address" },419      { "internalType": "address", "name": "operator", "type": "address" }420    ],421    "name": "isApprovedForAll",422    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],423    "stateMutability": "view",424    "type": "function"425  },426  {427    "inputs": [428      {429        "components": [430          { "internalType": "address", "name": "eth", "type": "address" },431          { "internalType": "uint256", "name": "sub", "type": "uint256" }432        ],433        "internalType": "struct CrossAddress",434        "name": "user",435        "type": "tuple"436      }437    ],438    "name": "isOwnerOrAdminCross",439    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],440    "stateMutability": "view",441    "type": "function"442  },443  {444    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],445    "name": "mint",446    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],447    "stateMutability": "nonpayable",448    "type": "function"449  },450  {451    "inputs": [452      {453        "components": [454          {455            "components": [456              { "internalType": "address", "name": "eth", "type": "address" },457              { "internalType": "uint256", "name": "sub", "type": "uint256" }458            ],459            "internalType": "struct CrossAddress",460            "name": "owner",461            "type": "tuple"462          },463          {464            "components": [465              { "internalType": "string", "name": "key", "type": "string" },466              { "internalType": "bytes", "name": "value", "type": "bytes" }467            ],468            "internalType": "struct Property[]",469            "name": "properties",470            "type": "tuple[]"471          }472        ],473        "internalType": "struct MintTokenData[]",474        "name": "tokenProperties",475        "type": "tuple[]"476      }477    ],478    "name": "mintBulkCross",479    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],480    "stateMutability": "nonpayable",481    "type": "function"482  },483  {484    "inputs": [485      {486        "components": [487          { "internalType": "address", "name": "eth", "type": "address" },488          { "internalType": "uint256", "name": "sub", "type": "uint256" }489        ],490        "internalType": "struct CrossAddress",491        "name": "to",492        "type": "tuple"493      },494      {495        "components": [496          { "internalType": "string", "name": "key", "type": "string" },497          { "internalType": "bytes", "name": "value", "type": "bytes" }498        ],499        "internalType": "struct Property[]",500        "name": "properties",501        "type": "tuple[]"502      }503    ],504    "name": "mintCross",505    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],506    "stateMutability": "nonpayable",507    "type": "function"508  },509  {510    "inputs": [511      { "internalType": "address", "name": "to", "type": "address" },512      { "internalType": "string", "name": "tokenUri", "type": "string" }513    ],514    "name": "mintWithTokenURI",515    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],516    "stateMutability": "nonpayable",517    "type": "function"518  },519  {520    "inputs": [],521    "name": "name",522    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],523    "stateMutability": "view",524    "type": "function"525  },526  {527    "inputs": [],528    "name": "nextTokenId",529    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],530    "stateMutability": "view",531    "type": "function"532  },533  {534    "inputs": [535      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }536    ],537    "name": "ownerOf",538    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],539    "stateMutability": "view",540    "type": "function"541  },542  {543    "inputs": [544      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }545    ],546    "name": "ownerOfCross",547    "outputs": [548      {549        "components": [550          { "internalType": "address", "name": "eth", "type": "address" },551          { "internalType": "uint256", "name": "sub", "type": "uint256" }552        ],553        "internalType": "struct CrossAddress",554        "name": "",555        "type": "tuple"556      }557    ],558    "stateMutability": "view",559    "type": "function"560  },561  {562    "inputs": [563      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },564      { "internalType": "string[]", "name": "keys", "type": "string[]" }565    ],566    "name": "properties",567    "outputs": [568      {569        "components": [570          { "internalType": "string", "name": "key", "type": "string" },571          { "internalType": "bytes", "name": "value", "type": "bytes" }572        ],573        "internalType": "struct Property[]",574        "name": "",575        "type": "tuple[]"576      }577    ],578    "stateMutability": "view",579    "type": "function"580  },581  {582    "inputs": [583      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },584      { "internalType": "string", "name": "key", "type": "string" }585    ],586    "name": "property",587    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],588    "stateMutability": "view",589    "type": "function"590  },591  {592    "inputs": [593      {594        "components": [595          { "internalType": "address", "name": "eth", "type": "address" },596          { "internalType": "uint256", "name": "sub", "type": "uint256" }597        ],598        "internalType": "struct CrossAddress",599        "name": "admin",600        "type": "tuple"601      }602    ],603    "name": "removeCollectionAdminCross",604    "outputs": [],605    "stateMutability": "nonpayable",606    "type": "function"607  },608  {609    "inputs": [],610    "name": "removeCollectionSponsor",611    "outputs": [],612    "stateMutability": "nonpayable",613    "type": "function"614  },615  {616    "inputs": [617      {618        "components": [619          { "internalType": "address", "name": "eth", "type": "address" },620          { "internalType": "uint256", "name": "sub", "type": "uint256" }621        ],622        "internalType": "struct CrossAddress",623        "name": "user",624        "type": "tuple"625      }626    ],627    "name": "removeFromCollectionAllowListCross",628    "outputs": [],629    "stateMutability": "nonpayable",630    "type": "function"631  },632  {633    "inputs": [634      { "internalType": "address", "name": "from", "type": "address" },635      { "internalType": "address", "name": "to", "type": "address" },636      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }637    ],638    "name": "safeTransferFrom",639    "outputs": [],640    "stateMutability": "nonpayable",641    "type": "function"642  },643  {644    "inputs": [645      { "internalType": "address", "name": "from", "type": "address" },646      { "internalType": "address", "name": "to", "type": "address" },647      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },648      { "internalType": "bytes", "name": "data", "type": "bytes" }649    ],650    "name": "safeTransferFrom",651    "outputs": [],652    "stateMutability": "nonpayable",653    "type": "function"654  },655  {656    "inputs": [657      { "internalType": "address", "name": "operator", "type": "address" },658      { "internalType": "bool", "name": "approved", "type": "bool" }659    ],660    "name": "setApprovalForAll",661    "outputs": [],662    "stateMutability": "nonpayable",663    "type": "function"664  },665  {666    "inputs": [667      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }668    ],669    "name": "setCollectionAccess",670    "outputs": [],671    "stateMutability": "nonpayable",672    "type": "function"673  },674  {675    "inputs": [676      {677        "components": [678          {679            "internalType": "enum CollectionLimitField",680            "name": "field",681            "type": "uint8"682          },683          {684            "components": [685              { "internalType": "bool", "name": "status", "type": "bool" },686              { "internalType": "uint256", "name": "value", "type": "uint256" }687            ],688            "internalType": "struct OptionUint256",689            "name": "value",690            "type": "tuple"691          }692        ],693        "internalType": "struct CollectionLimit",694        "name": "limit",695        "type": "tuple"696      }697    ],698    "name": "setCollectionLimit",699    "outputs": [],700    "stateMutability": "nonpayable",701    "type": "function"702  },703  {704    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],705    "name": "setCollectionMintMode",706    "outputs": [],707    "stateMutability": "nonpayable",708    "type": "function"709  },710  {711    "inputs": [712      {713        "components": [714          { "internalType": "bool", "name": "token_owner", "type": "bool" },715          {716            "internalType": "bool",717            "name": "collection_admin",718            "type": "bool"719          },720          {721            "internalType": "address[]",722            "name": "restricted",723            "type": "address[]"724          }725        ],726        "internalType": "struct CollectionNestingAndPermission",727        "name": "collectionNestingAndPermissions",728        "type": "tuple"729      }730    ],731    "name": "setCollectionNesting",732    "outputs": [],733    "stateMutability": "nonpayable",734    "type": "function"735  },736  {737    "inputs": [738      {739        "components": [740          { "internalType": "string", "name": "key", "type": "string" },741          { "internalType": "bytes", "name": "value", "type": "bytes" }742        ],743        "internalType": "struct Property[]",744        "name": "properties",745        "type": "tuple[]"746      }747    ],748    "name": "setCollectionProperties",749    "outputs": [],750    "stateMutability": "nonpayable",751    "type": "function"752  },753  {754    "inputs": [755      {756        "components": [757          { "internalType": "address", "name": "eth", "type": "address" },758          { "internalType": "uint256", "name": "sub", "type": "uint256" }759        ],760        "internalType": "struct CrossAddress",761        "name": "sponsor",762        "type": "tuple"763      }764    ],765    "name": "setCollectionSponsorCross",766    "outputs": [],767    "stateMutability": "nonpayable",768    "type": "function"769  },770  {771    "inputs": [772      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },773      {774        "components": [775          { "internalType": "string", "name": "key", "type": "string" },776          { "internalType": "bytes", "name": "value", "type": "bytes" }777        ],778        "internalType": "struct Property[]",779        "name": "properties",780        "type": "tuple[]"781      }782    ],783    "name": "setProperties",784    "outputs": [],785    "stateMutability": "nonpayable",786    "type": "function"787  },788  {789    "inputs": [790      {791        "components": [792          { "internalType": "string", "name": "key", "type": "string" },793          {794            "components": [795              {796                "internalType": "enum TokenPermissionField",797                "name": "code",798                "type": "uint8"799              },800              { "internalType": "bool", "name": "value", "type": "bool" }801            ],802            "internalType": "struct PropertyPermission[]",803            "name": "permissions",804            "type": "tuple[]"805          }806        ],807        "internalType": "struct TokenPropertyPermission[]",808        "name": "permissions",809        "type": "tuple[]"810      }811    ],812    "name": "setTokenPropertyPermissions",813    "outputs": [],814    "stateMutability": "nonpayable",815    "type": "function"816  },817  {818    "inputs": [819      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }820    ],821    "name": "supportsInterface",822    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],823    "stateMutability": "view",824    "type": "function"825  },826  {827    "inputs": [],828    "name": "symbol",829    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],830    "stateMutability": "view",831    "type": "function"832  },833  {834    "inputs": [835      { "internalType": "uint256", "name": "index", "type": "uint256" }836    ],837    "name": "tokenByIndex",838    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],839    "stateMutability": "view",840    "type": "function"841  },842  {843    "inputs": [844      { "internalType": "uint256", "name": "token", "type": "uint256" }845    ],846    "name": "tokenContractAddress",847    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],848    "stateMutability": "view",849    "type": "function"850  },851  {852    "inputs": [853      { "internalType": "address", "name": "owner", "type": "address" },854      { "internalType": "uint256", "name": "index", "type": "uint256" }855    ],856    "name": "tokenOfOwnerByIndex",857    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],858    "stateMutability": "view",859    "type": "function"860  },861  {862    "inputs": [],863    "name": "tokenPropertyPermissions",864    "outputs": [865      {866        "components": [867          { "internalType": "string", "name": "key", "type": "string" },868          {869            "components": [870              {871                "internalType": "enum TokenPermissionField",872                "name": "code",873                "type": "uint8"874              },875              { "internalType": "bool", "name": "value", "type": "bool" }876            ],877            "internalType": "struct PropertyPermission[]",878            "name": "permissions",879            "type": "tuple[]"880          }881        ],882        "internalType": "struct TokenPropertyPermission[]",883        "name": "",884        "type": "tuple[]"885      }886    ],887    "stateMutability": "view",888    "type": "function"889  },890  {891    "inputs": [892      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }893    ],894    "name": "tokenURI",895    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],896    "stateMutability": "view",897    "type": "function"898  },899  {900    "inputs": [],901    "name": "totalSupply",902    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],903    "stateMutability": "view",904    "type": "function"905  },906  {907    "inputs": [908      { "internalType": "address", "name": "to", "type": "address" },909      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }910    ],911    "name": "transfer",912    "outputs": [],913    "stateMutability": "nonpayable",914    "type": "function"915  },916  {917    "inputs": [918      {919        "components": [920          { "internalType": "address", "name": "eth", "type": "address" },921          { "internalType": "uint256", "name": "sub", "type": "uint256" }922        ],923        "internalType": "struct CrossAddress",924        "name": "to",925        "type": "tuple"926      },927      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }928    ],929    "name": "transferCross",930    "outputs": [],931    "stateMutability": "nonpayable",932    "type": "function"933  },934  {935    "inputs": [936      { "internalType": "address", "name": "from", "type": "address" },937      { "internalType": "address", "name": "to", "type": "address" },938      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }939    ],940    "name": "transferFrom",941    "outputs": [],942    "stateMutability": "nonpayable",943    "type": "function"944  },945  {946    "inputs": [947      {948        "components": [949          { "internalType": "address", "name": "eth", "type": "address" },950          { "internalType": "uint256", "name": "sub", "type": "uint256" }951        ],952        "internalType": "struct CrossAddress",953        "name": "from",954        "type": "tuple"955      },956      {957        "components": [958          { "internalType": "address", "name": "eth", "type": "address" },959          { "internalType": "uint256", "name": "sub", "type": "uint256" }960        ],961        "internalType": "struct CrossAddress",962        "name": "to",963        "type": "tuple"964      },965      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }966    ],967    "name": "transferFromCross",968    "outputs": [],969    "stateMutability": "nonpayable",970    "type": "function"971  },972  {973    "inputs": [],974    "name": "uniqueCollectionType",975    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],976    "stateMutability": "view",977    "type": "function"978  }979]
after · tests/src/eth/abi/reFungible.json
1[2  {3    "anonymous": false,4    "inputs": [5      {6        "indexed": true,7        "internalType": "address",8        "name": "owner",9        "type": "address"10      },11      {12        "indexed": true,13        "internalType": "address",14        "name": "approved",15        "type": "address"16      },17      {18        "indexed": true,19        "internalType": "uint256",20        "name": "tokenId",21        "type": "uint256"22      }23    ],24    "name": "Approval",25    "type": "event"26  },27  {28    "anonymous": false,29    "inputs": [30      {31        "indexed": true,32        "internalType": "address",33        "name": "owner",34        "type": "address"35      },36      {37        "indexed": true,38        "internalType": "address",39        "name": "operator",40        "type": "address"41      },42      {43        "indexed": false,44        "internalType": "bool",45        "name": "approved",46        "type": "bool"47      }48    ],49    "name": "ApprovalForAll",50    "type": "event"51  },52  {53    "anonymous": false,54    "inputs": [55      {56        "indexed": true,57        "internalType": "uint256",58        "name": "tokenId",59        "type": "uint256"60      }61    ],62    "name": "TokenChanged",63    "type": "event"64  },65  {66    "anonymous": false,67    "inputs": [68      {69        "indexed": true,70        "internalType": "address",71        "name": "from",72        "type": "address"73      },74      {75        "indexed": true,76        "internalType": "address",77        "name": "to",78        "type": "address"79      },80      {81        "indexed": true,82        "internalType": "uint256",83        "name": "tokenId",84        "type": "uint256"85      }86    ],87    "name": "Transfer",88    "type": "event"89  },90  {91    "inputs": [92      {93        "components": [94          { "internalType": "address", "name": "eth", "type": "address" },95          { "internalType": "uint256", "name": "sub", "type": "uint256" }96        ],97        "internalType": "struct CrossAddress",98        "name": "newAdmin",99        "type": "tuple"100      }101    ],102    "name": "addCollectionAdminCross",103    "outputs": [],104    "stateMutability": "nonpayable",105    "type": "function"106  },107  {108    "inputs": [109      {110        "components": [111          { "internalType": "address", "name": "eth", "type": "address" },112          { "internalType": "uint256", "name": "sub", "type": "uint256" }113        ],114        "internalType": "struct CrossAddress",115        "name": "user",116        "type": "tuple"117      }118    ],119    "name": "addToCollectionAllowListCross",120    "outputs": [],121    "stateMutability": "nonpayable",122    "type": "function"123  },124  {125    "inputs": [126      {127        "components": [128          { "internalType": "address", "name": "eth", "type": "address" },129          { "internalType": "uint256", "name": "sub", "type": "uint256" }130        ],131        "internalType": "struct CrossAddress",132        "name": "user",133        "type": "tuple"134      }135    ],136    "name": "allowlistedCross",137    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],138    "stateMutability": "view",139    "type": "function"140  },141  {142    "inputs": [143      { "internalType": "address", "name": "approved", "type": "address" },144      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }145    ],146    "name": "approve",147    "outputs": [],148    "stateMutability": "nonpayable",149    "type": "function"150  },151  {152    "inputs": [153      { "internalType": "address", "name": "owner", "type": "address" }154    ],155    "name": "balanceOf",156    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],157    "stateMutability": "view",158    "type": "function"159  },160  {161    "inputs": [162      {163        "components": [164          { "internalType": "address", "name": "eth", "type": "address" },165          { "internalType": "uint256", "name": "sub", "type": "uint256" }166        ],167        "internalType": "struct CrossAddress",168        "name": "owner",169        "type": "tuple"170      }171    ],172    "name": "balanceOfCross",173    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],174    "stateMutability": "view",175    "type": "function"176  },177  {178    "inputs": [179      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }180    ],181    "name": "burn",182    "outputs": [],183    "stateMutability": "nonpayable",184    "type": "function"185  },186  {187    "inputs": [188      {189        "components": [190          { "internalType": "address", "name": "eth", "type": "address" },191          { "internalType": "uint256", "name": "sub", "type": "uint256" }192        ],193        "internalType": "struct CrossAddress",194        "name": "from",195        "type": "tuple"196      },197      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }198    ],199    "name": "burnFromCross",200    "outputs": [],201    "stateMutability": "nonpayable",202    "type": "function"203  },204  {205    "inputs": [206      {207        "components": [208          { "internalType": "address", "name": "eth", "type": "address" },209          { "internalType": "uint256", "name": "sub", "type": "uint256" }210        ],211        "internalType": "struct CrossAddress",212        "name": "newOwner",213        "type": "tuple"214      }215    ],216    "name": "changeCollectionOwnerCross",217    "outputs": [],218    "stateMutability": "nonpayable",219    "type": "function"220  },221  {222    "inputs": [],223    "name": "collectionAdmins",224    "outputs": [225      {226        "components": [227          { "internalType": "address", "name": "eth", "type": "address" },228          { "internalType": "uint256", "name": "sub", "type": "uint256" }229        ],230        "internalType": "struct CrossAddress[]",231        "name": "",232        "type": "tuple[]"233      }234    ],235    "stateMutability": "view",236    "type": "function"237  },238  {239    "inputs": [],240    "name": "collectionHelperAddress",241    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],242    "stateMutability": "view",243    "type": "function"244  },245  {246    "inputs": [],247    "name": "collectionLimits",248    "outputs": [249      {250        "components": [251          {252            "internalType": "enum CollectionLimitField",253            "name": "field",254            "type": "uint8"255          },256          {257            "components": [258              { "internalType": "bool", "name": "status", "type": "bool" },259              { "internalType": "uint256", "name": "value", "type": "uint256" }260            ],261            "internalType": "struct OptionUint256",262            "name": "value",263            "type": "tuple"264          }265        ],266        "internalType": "struct CollectionLimit[]",267        "name": "",268        "type": "tuple[]"269      }270    ],271    "stateMutability": "view",272    "type": "function"273  },274  {275    "inputs": [],276    "name": "collectionNesting",277    "outputs": [278      {279        "components": [280          { "internalType": "bool", "name": "token_owner", "type": "bool" },281          {282            "internalType": "bool",283            "name": "collection_admin",284            "type": "bool"285          },286          {287            "internalType": "address[]",288            "name": "restricted",289            "type": "address[]"290          }291        ],292        "internalType": "struct CollectionNestingAndPermission",293        "name": "",294        "type": "tuple"295      }296    ],297    "stateMutability": "view",298    "type": "function"299  },300  {301    "inputs": [],302    "name": "collectionOwner",303    "outputs": [304      {305        "components": [306          { "internalType": "address", "name": "eth", "type": "address" },307          { "internalType": "uint256", "name": "sub", "type": "uint256" }308        ],309        "internalType": "struct CrossAddress",310        "name": "",311        "type": "tuple"312      }313    ],314    "stateMutability": "view",315    "type": "function"316  },317  {318    "inputs": [319      { "internalType": "string[]", "name": "keys", "type": "string[]" }320    ],321    "name": "collectionProperties",322    "outputs": [323      {324        "components": [325          { "internalType": "string", "name": "key", "type": "string" },326          { "internalType": "bytes", "name": "value", "type": "bytes" }327        ],328        "internalType": "struct Property[]",329        "name": "",330        "type": "tuple[]"331      }332    ],333    "stateMutability": "view",334    "type": "function"335  },336  {337    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],338    "name": "collectionProperty",339    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],340    "stateMutability": "view",341    "type": "function"342  },343  {344    "inputs": [],345    "name": "collectionSponsor",346    "outputs": [347      {348        "components": [349          { "internalType": "address", "name": "eth", "type": "address" },350          { "internalType": "uint256", "name": "sub", "type": "uint256" }351        ],352        "internalType": "struct CrossAddress",353        "name": "",354        "type": "tuple"355      }356    ],357    "stateMutability": "view",358    "type": "function"359  },360  {361    "inputs": [],362    "name": "confirmCollectionSponsorship",363    "outputs": [],364    "stateMutability": "nonpayable",365    "type": "function"366  },367  {368    "inputs": [],369    "name": "contractAddress",370    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],371    "stateMutability": "view",372    "type": "function"373  },374  {375    "inputs": [376      { "internalType": "string[]", "name": "keys", "type": "string[]" }377    ],378    "name": "deleteCollectionProperties",379    "outputs": [],380    "stateMutability": "nonpayable",381    "type": "function"382  },383  {384    "inputs": [385      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },386      { "internalType": "string[]", "name": "keys", "type": "string[]" }387    ],388    "name": "deleteProperties",389    "outputs": [],390    "stateMutability": "nonpayable",391    "type": "function"392  },393  {394    "inputs": [],395    "name": "description",396    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],397    "stateMutability": "view",398    "type": "function"399  },400  {401    "inputs": [402      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }403    ],404    "name": "getApproved",405    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],406    "stateMutability": "view",407    "type": "function"408  },409  {410    "inputs": [],411    "name": "hasCollectionPendingSponsor",412    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],413    "stateMutability": "view",414    "type": "function"415  },416  {417    "inputs": [418      { "internalType": "address", "name": "owner", "type": "address" },419      { "internalType": "address", "name": "operator", "type": "address" }420    ],421    "name": "isApprovedForAll",422    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],423    "stateMutability": "view",424    "type": "function"425  },426  {427    "inputs": [428      {429        "components": [430          { "internalType": "address", "name": "eth", "type": "address" },431          { "internalType": "uint256", "name": "sub", "type": "uint256" }432        ],433        "internalType": "struct CrossAddress",434        "name": "user",435        "type": "tuple"436      }437    ],438    "name": "isOwnerOrAdminCross",439    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],440    "stateMutability": "view",441    "type": "function"442  },443  {444    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],445    "name": "mint",446    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],447    "stateMutability": "nonpayable",448    "type": "function"449  },450  {451    "inputs": [452      {453        "components": [454          {455            "components": [456              {457                "components": [458                  {459                    "internalType": "address",460                    "name": "eth",461                    "type": "address"462                  },463                  {464                    "internalType": "uint256",465                    "name": "sub",466                    "type": "uint256"467                  }468                ],469                "internalType": "struct CrossAddress",470                "name": "owner",471                "type": "tuple"472              },473              { "internalType": "uint128", "name": "pieces", "type": "uint128" }474            ],475            "internalType": "struct OwnerPieces[]",476            "name": "owners",477            "type": "tuple[]"478          },479          {480            "components": [481              { "internalType": "string", "name": "key", "type": "string" },482              { "internalType": "bytes", "name": "value", "type": "bytes" }483            ],484            "internalType": "struct Property[]",485            "name": "properties",486            "type": "tuple[]"487          }488        ],489        "internalType": "struct MintTokenData[]",490        "name": "tokenProperties",491        "type": "tuple[]"492      }493    ],494    "name": "mintBulkCross",495    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],496    "stateMutability": "nonpayable",497    "type": "function"498  },499  {500    "inputs": [501      {502        "components": [503          { "internalType": "address", "name": "eth", "type": "address" },504          { "internalType": "uint256", "name": "sub", "type": "uint256" }505        ],506        "internalType": "struct CrossAddress",507        "name": "to",508        "type": "tuple"509      },510      {511        "components": [512          { "internalType": "string", "name": "key", "type": "string" },513          { "internalType": "bytes", "name": "value", "type": "bytes" }514        ],515        "internalType": "struct Property[]",516        "name": "properties",517        "type": "tuple[]"518      }519    ],520    "name": "mintCross",521    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],522    "stateMutability": "nonpayable",523    "type": "function"524  },525  {526    "inputs": [527      { "internalType": "address", "name": "to", "type": "address" },528      { "internalType": "string", "name": "tokenUri", "type": "string" }529    ],530    "name": "mintWithTokenURI",531    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],532    "stateMutability": "nonpayable",533    "type": "function"534  },535  {536    "inputs": [],537    "name": "name",538    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],539    "stateMutability": "view",540    "type": "function"541  },542  {543    "inputs": [],544    "name": "nextTokenId",545    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],546    "stateMutability": "view",547    "type": "function"548  },549  {550    "inputs": [551      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }552    ],553    "name": "ownerOf",554    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],555    "stateMutability": "view",556    "type": "function"557  },558  {559    "inputs": [560      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }561    ],562    "name": "ownerOfCross",563    "outputs": [564      {565        "components": [566          { "internalType": "address", "name": "eth", "type": "address" },567          { "internalType": "uint256", "name": "sub", "type": "uint256" }568        ],569        "internalType": "struct CrossAddress",570        "name": "",571        "type": "tuple"572      }573    ],574    "stateMutability": "view",575    "type": "function"576  },577  {578    "inputs": [579      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },580      { "internalType": "string[]", "name": "keys", "type": "string[]" }581    ],582    "name": "properties",583    "outputs": [584      {585        "components": [586          { "internalType": "string", "name": "key", "type": "string" },587          { "internalType": "bytes", "name": "value", "type": "bytes" }588        ],589        "internalType": "struct Property[]",590        "name": "",591        "type": "tuple[]"592      }593    ],594    "stateMutability": "view",595    "type": "function"596  },597  {598    "inputs": [599      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },600      { "internalType": "string", "name": "key", "type": "string" }601    ],602    "name": "property",603    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],604    "stateMutability": "view",605    "type": "function"606  },607  {608    "inputs": [609      {610        "components": [611          { "internalType": "address", "name": "eth", "type": "address" },612          { "internalType": "uint256", "name": "sub", "type": "uint256" }613        ],614        "internalType": "struct CrossAddress",615        "name": "admin",616        "type": "tuple"617      }618    ],619    "name": "removeCollectionAdminCross",620    "outputs": [],621    "stateMutability": "nonpayable",622    "type": "function"623  },624  {625    "inputs": [],626    "name": "removeCollectionSponsor",627    "outputs": [],628    "stateMutability": "nonpayable",629    "type": "function"630  },631  {632    "inputs": [633      {634        "components": [635          { "internalType": "address", "name": "eth", "type": "address" },636          { "internalType": "uint256", "name": "sub", "type": "uint256" }637        ],638        "internalType": "struct CrossAddress",639        "name": "user",640        "type": "tuple"641      }642    ],643    "name": "removeFromCollectionAllowListCross",644    "outputs": [],645    "stateMutability": "nonpayable",646    "type": "function"647  },648  {649    "inputs": [650      { "internalType": "address", "name": "from", "type": "address" },651      { "internalType": "address", "name": "to", "type": "address" },652      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }653    ],654    "name": "safeTransferFrom",655    "outputs": [],656    "stateMutability": "nonpayable",657    "type": "function"658  },659  {660    "inputs": [661      { "internalType": "address", "name": "from", "type": "address" },662      { "internalType": "address", "name": "to", "type": "address" },663      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },664      { "internalType": "bytes", "name": "data", "type": "bytes" }665    ],666    "name": "safeTransferFrom",667    "outputs": [],668    "stateMutability": "nonpayable",669    "type": "function"670  },671  {672    "inputs": [673      { "internalType": "address", "name": "operator", "type": "address" },674      { "internalType": "bool", "name": "approved", "type": "bool" }675    ],676    "name": "setApprovalForAll",677    "outputs": [],678    "stateMutability": "nonpayable",679    "type": "function"680  },681  {682    "inputs": [683      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }684    ],685    "name": "setCollectionAccess",686    "outputs": [],687    "stateMutability": "nonpayable",688    "type": "function"689  },690  {691    "inputs": [692      {693        "components": [694          {695            "internalType": "enum CollectionLimitField",696            "name": "field",697            "type": "uint8"698          },699          {700            "components": [701              { "internalType": "bool", "name": "status", "type": "bool" },702              { "internalType": "uint256", "name": "value", "type": "uint256" }703            ],704            "internalType": "struct OptionUint256",705            "name": "value",706            "type": "tuple"707          }708        ],709        "internalType": "struct CollectionLimit",710        "name": "limit",711        "type": "tuple"712      }713    ],714    "name": "setCollectionLimit",715    "outputs": [],716    "stateMutability": "nonpayable",717    "type": "function"718  },719  {720    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],721    "name": "setCollectionMintMode",722    "outputs": [],723    "stateMutability": "nonpayable",724    "type": "function"725  },726  {727    "inputs": [728      {729        "components": [730          { "internalType": "bool", "name": "token_owner", "type": "bool" },731          {732            "internalType": "bool",733            "name": "collection_admin",734            "type": "bool"735          },736          {737            "internalType": "address[]",738            "name": "restricted",739            "type": "address[]"740          }741        ],742        "internalType": "struct CollectionNestingAndPermission",743        "name": "collectionNestingAndPermissions",744        "type": "tuple"745      }746    ],747    "name": "setCollectionNesting",748    "outputs": [],749    "stateMutability": "nonpayable",750    "type": "function"751  },752  {753    "inputs": [754      {755        "components": [756          { "internalType": "string", "name": "key", "type": "string" },757          { "internalType": "bytes", "name": "value", "type": "bytes" }758        ],759        "internalType": "struct Property[]",760        "name": "properties",761        "type": "tuple[]"762      }763    ],764    "name": "setCollectionProperties",765    "outputs": [],766    "stateMutability": "nonpayable",767    "type": "function"768  },769  {770    "inputs": [771      {772        "components": [773          { "internalType": "address", "name": "eth", "type": "address" },774          { "internalType": "uint256", "name": "sub", "type": "uint256" }775        ],776        "internalType": "struct CrossAddress",777        "name": "sponsor",778        "type": "tuple"779      }780    ],781    "name": "setCollectionSponsorCross",782    "outputs": [],783    "stateMutability": "nonpayable",784    "type": "function"785  },786  {787    "inputs": [788      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },789      {790        "components": [791          { "internalType": "string", "name": "key", "type": "string" },792          { "internalType": "bytes", "name": "value", "type": "bytes" }793        ],794        "internalType": "struct Property[]",795        "name": "properties",796        "type": "tuple[]"797      }798    ],799    "name": "setProperties",800    "outputs": [],801    "stateMutability": "nonpayable",802    "type": "function"803  },804  {805    "inputs": [806      {807        "components": [808          { "internalType": "string", "name": "key", "type": "string" },809          {810            "components": [811              {812                "internalType": "enum TokenPermissionField",813                "name": "code",814                "type": "uint8"815              },816              { "internalType": "bool", "name": "value", "type": "bool" }817            ],818            "internalType": "struct PropertyPermission[]",819            "name": "permissions",820            "type": "tuple[]"821          }822        ],823        "internalType": "struct TokenPropertyPermission[]",824        "name": "permissions",825        "type": "tuple[]"826      }827    ],828    "name": "setTokenPropertyPermissions",829    "outputs": [],830    "stateMutability": "nonpayable",831    "type": "function"832  },833  {834    "inputs": [835      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }836    ],837    "name": "supportsInterface",838    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],839    "stateMutability": "view",840    "type": "function"841  },842  {843    "inputs": [],844    "name": "symbol",845    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],846    "stateMutability": "view",847    "type": "function"848  },849  {850    "inputs": [851      { "internalType": "uint256", "name": "index", "type": "uint256" }852    ],853    "name": "tokenByIndex",854    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],855    "stateMutability": "view",856    "type": "function"857  },858  {859    "inputs": [860      { "internalType": "uint256", "name": "token", "type": "uint256" }861    ],862    "name": "tokenContractAddress",863    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],864    "stateMutability": "view",865    "type": "function"866  },867  {868    "inputs": [869      { "internalType": "address", "name": "owner", "type": "address" },870      { "internalType": "uint256", "name": "index", "type": "uint256" }871    ],872    "name": "tokenOfOwnerByIndex",873    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],874    "stateMutability": "view",875    "type": "function"876  },877  {878    "inputs": [],879    "name": "tokenPropertyPermissions",880    "outputs": [881      {882        "components": [883          { "internalType": "string", "name": "key", "type": "string" },884          {885            "components": [886              {887                "internalType": "enum TokenPermissionField",888                "name": "code",889                "type": "uint8"890              },891              { "internalType": "bool", "name": "value", "type": "bool" }892            ],893            "internalType": "struct PropertyPermission[]",894            "name": "permissions",895            "type": "tuple[]"896          }897        ],898        "internalType": "struct TokenPropertyPermission[]",899        "name": "",900        "type": "tuple[]"901      }902    ],903    "stateMutability": "view",904    "type": "function"905  },906  {907    "inputs": [908      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }909    ],910    "name": "tokenURI",911    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],912    "stateMutability": "view",913    "type": "function"914  },915  {916    "inputs": [],917    "name": "totalSupply",918    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],919    "stateMutability": "view",920    "type": "function"921  },922  {923    "inputs": [924      { "internalType": "address", "name": "to", "type": "address" },925      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }926    ],927    "name": "transfer",928    "outputs": [],929    "stateMutability": "nonpayable",930    "type": "function"931  },932  {933    "inputs": [934      {935        "components": [936          { "internalType": "address", "name": "eth", "type": "address" },937          { "internalType": "uint256", "name": "sub", "type": "uint256" }938        ],939        "internalType": "struct CrossAddress",940        "name": "to",941        "type": "tuple"942      },943      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }944    ],945    "name": "transferCross",946    "outputs": [],947    "stateMutability": "nonpayable",948    "type": "function"949  },950  {951    "inputs": [952      { "internalType": "address", "name": "from", "type": "address" },953      { "internalType": "address", "name": "to", "type": "address" },954      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }955    ],956    "name": "transferFrom",957    "outputs": [],958    "stateMutability": "nonpayable",959    "type": "function"960  },961  {962    "inputs": [963      {964        "components": [965          { "internalType": "address", "name": "eth", "type": "address" },966          { "internalType": "uint256", "name": "sub", "type": "uint256" }967        ],968        "internalType": "struct CrossAddress",969        "name": "from",970        "type": "tuple"971      },972      {973        "components": [974          { "internalType": "address", "name": "eth", "type": "address" },975          { "internalType": "uint256", "name": "sub", "type": "uint256" }976        ],977        "internalType": "struct CrossAddress",978        "name": "to",979        "type": "tuple"980      },981      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }982    ],983    "name": "transferFromCross",984    "outputs": [],985    "stateMutability": "nonpayable",986    "type": "function"987  },988  {989    "inputs": [],990    "name": "uniqueCollectionType",991    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],992    "stateMutability": "view",993    "type": "function"994  }995]
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- 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;
 }
 
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- 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
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- 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},
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- 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}`);
       }