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

difftreelog

Merge pull request #1054 from UniqueNetwork/feature/refactor-tests-eth

Yaroslav Bolyukin2024-02-13parents: #667f02f #4da0499.patch.diff
in: master

111 files changed

modifiedMakefilediffbeforeafterboth
--- a/Makefile
+++ b/Makefile
@@ -7,25 +7,25 @@
 	@echo "  bench-unique"
 
 NATIVE_FUNGIBLE_EVM_STUBS=./pallets/balances-adapter/src/stubs
-NATIVE_FUNGIBLE_EVM_ABI=./js-packages/tests/eth/abi/nativeFungible.json
+NATIVE_FUNGIBLE_EVM_ABI=./js-packages/evm-abi/abi/nativeFungible.json
 
 FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs
-FUNGIBLE_EVM_ABI=./js-packages/tests/eth/abi/fungible.json
+FUNGIBLE_EVM_ABI=./js-packages/evm-abi/abi/fungible.json
 
 NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs
-NONFUNGIBLE_EVM_ABI=./js-packages/tests/eth/abi/nonFungible.json
+NONFUNGIBLE_EVM_ABI=./js-packages/evm-abi/abi/nonFungible.json
 
 REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs
-REFUNGIBLE_EVM_ABI=./js-packages/tests/eth/abi/reFungible.json
-REFUNGIBLE_TOKEN_EVM_ABI=./js-packages/tests/eth/abi/reFungibleToken.json
+REFUNGIBLE_EVM_ABI=./js-packages/evm-abi/abi/reFungible.json
+REFUNGIBLE_TOKEN_EVM_ABI=./js-packages/evm-abi/abi/reFungibleToken.json
 
 CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/
-CONTRACT_HELPERS_ABI=./js-packages/tests/eth/abi/contractHelpers.json
+CONTRACT_HELPERS_ABI=./js-packages/evm-abi/abi/contractHelpers.json
 
 COLLECTION_HELPER_STUBS=./pallets/unique/src/eth/stubs/
-COLLECTION_HELPER_ABI=./js-packages/tests/eth/abi/collectionHelpers.json
+COLLECTION_HELPER_ABI=./js-packages/evm-abi/abi/collectionHelpers.json
 
-TESTS_API=./js-packages/tests/eth/api/
+TESTS_API=./js-packages/evm-abi/api/
 
 .PHONY: regenerate_solidity
 regenerate_solidity: UniqueFungible.sol UniqueNFT.sol UniqueRefungible.sol UniqueRefungibleToken.sol ContractHelpers.sol CollectionHelpers.sol
addedjs-packages/evm-abi/abi/collectionHelpers.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/collectionHelpers.json
@@ -0,0 +1,267 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      }
+    ],
+    "name": "CollectionChanged",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      }
+    ],
+    "name": "CollectionCreated",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "collectionId",
+        "type": "address"
+      }
+    ],
+    "name": "CollectionDestroyed",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
+    ],
+    "name": "collectionAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionCreationFee",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "collectionAddress",
+        "type": "address"
+      }
+    ],
+    "name": "collectionId",
+    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "name", "type": "string" },
+          { "internalType": "string", "name": "description", "type": "string" },
+          {
+            "internalType": "string",
+            "name": "token_prefix",
+            "type": "string"
+          },
+          {
+            "internalType": "enum CollectionMode",
+            "name": "mode",
+            "type": "uint8"
+          },
+          { "internalType": "uint8", "name": "decimals", "type": "uint8" },
+          {
+            "components": [
+              { "internalType": "string", "name": "key", "type": "string" },
+              { "internalType": "bytes", "name": "value", "type": "bytes" }
+            ],
+            "internalType": "struct Property[]",
+            "name": "properties",
+            "type": "tuple[]"
+          },
+          {
+            "components": [
+              { "internalType": "string", "name": "key", "type": "string" },
+              {
+                "components": [
+                  {
+                    "internalType": "enum TokenPermissionField",
+                    "name": "code",
+                    "type": "uint8"
+                  },
+                  { "internalType": "bool", "name": "value", "type": "bool" }
+                ],
+                "internalType": "struct PropertyPermission[]",
+                "name": "permissions",
+                "type": "tuple[]"
+              }
+            ],
+            "internalType": "struct TokenPropertyPermission[]",
+            "name": "token_property_permissions",
+            "type": "tuple[]"
+          },
+          {
+            "components": [
+              { "internalType": "address", "name": "eth", "type": "address" },
+              { "internalType": "uint256", "name": "sub", "type": "uint256" }
+            ],
+            "internalType": "struct CrossAddress[]",
+            "name": "admin_list",
+            "type": "tuple[]"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "token_owner", "type": "bool" },
+              {
+                "internalType": "bool",
+                "name": "collection_admin",
+                "type": "bool"
+              },
+              {
+                "internalType": "address[]",
+                "name": "restricted",
+                "type": "address[]"
+              }
+            ],
+            "internalType": "struct CollectionNestingAndPermission",
+            "name": "nesting_settings",
+            "type": "tuple"
+          },
+          {
+            "components": [
+              {
+                "internalType": "enum CollectionLimitField",
+                "name": "field",
+                "type": "uint8"
+              },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct CollectionLimitValue[]",
+            "name": "limits",
+            "type": "tuple[]"
+          },
+          {
+            "components": [
+              { "internalType": "address", "name": "eth", "type": "address" },
+              { "internalType": "uint256", "name": "sub", "type": "uint256" }
+            ],
+            "internalType": "struct CrossAddress",
+            "name": "pending_sponsor",
+            "type": "tuple"
+          },
+          {
+            "internalType": "CollectionFlags",
+            "name": "flags",
+            "type": "uint8"
+          }
+        ],
+        "internalType": "struct CreateCollectionData",
+        "name": "data",
+        "type": "tuple"
+      }
+    ],
+    "name": "createCollection",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "payable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "name", "type": "string" },
+      { "internalType": "uint8", "name": "decimals", "type": "uint8" },
+      { "internalType": "string", "name": "description", "type": "string" },
+      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+    ],
+    "name": "createFTCollection",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "payable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "name", "type": "string" },
+      { "internalType": "string", "name": "description", "type": "string" },
+      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+    ],
+    "name": "createNFTCollection",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "payable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "name", "type": "string" },
+      { "internalType": "string", "name": "description", "type": "string" },
+      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
+    ],
+    "name": "createRFTCollection",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "payable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "collectionAddress",
+        "type": "address"
+      }
+    ],
+    "name": "destroyCollection",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "collectionAddress",
+        "type": "address"
+      }
+    ],
+    "name": "isCollectionExist",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "collection", "type": "address" },
+      { "internalType": "string", "name": "baseUri", "type": "string" }
+    ],
+    "name": "makeCollectionERC721MetadataCompatible",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/contractHelpers.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/contractHelpers.json
@@ -0,0 +1,326 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorRemoved",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "address",
+        "name": "sponsor",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorSet",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "address",
+        "name": "sponsor",
+        "type": "address"
+      }
+    ],
+    "name": "ContractSponsorshipConfirmed",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "allowed",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "allowlistEnabled",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "confirmSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "contractOwner",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "hasPendingSponsor",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "hasSponsor",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "removeSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "selfSponsoredEnable",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "uint256", "name": "feeLimit", "type": "uint256" }
+    ],
+    "name": "setSponsoringFeeLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      {
+        "internalType": "enum SponsoringModeT",
+        "name": "mode",
+        "type": "uint8"
+      }
+    ],
+    "name": "setSponsoringMode",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }
+    ],
+    "name": "setSponsoringRateLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "sponsor",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "status", "type": "bool" },
+          {
+            "components": [
+              { "internalType": "address", "name": "eth", "type": "address" },
+              { "internalType": "uint256", "name": "sub", "type": "uint256" }
+            ],
+            "internalType": "struct CrossAddress",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct OptionCrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "sponsoringEnabled",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "sponsoringFeeLimit",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      }
+    ],
+    "name": "sponsoringRateLimit",
+    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "address", "name": "user", "type": "address" },
+      { "internalType": "bool", "name": "isAllowed", "type": "bool" }
+    ],
+    "name": "toggleAllowed",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "internalType": "address",
+        "name": "contractAddress",
+        "type": "address"
+      },
+      { "internalType": "bool", "name": "enabled", "type": "bool" }
+    ],
+    "name": "toggleAllowlist",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/fungible.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/fungible.json
@@ -0,0 +1,722 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "spender",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newAdmin",
+        "type": "tuple"
+      }
+    ],
+    "name": "addCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "addToCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "spender", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "spender",
+        "type": "tuple"
+      }
+    ],
+    "name": "allowanceCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "allowlistedCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "spender", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "spender",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approveCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      }
+    ],
+    "name": "balanceOfCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newOwner",
+        "type": "tuple"
+      }
+    ],
+    "name": "changeCollectionOwnerCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionAdmins",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionLimits",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNesting",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionOwner",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "collectionProperties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "collectionProperty",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionSponsor",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "confirmCollectionSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "contractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "deleteCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "description",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "hasCollectionPendingSponsor",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "isOwnerOrAdminCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "mint",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "to", "type": "address" },
+          { "internalType": "uint256", "name": "amount", "type": "uint256" }
+        ],
+        "internalType": "struct AmountForAddress[]",
+        "name": "amounts",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulk",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "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" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "admin",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "removeCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeFromCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
+    "name": "setCollectionAccess",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit",
+        "name": "limit",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+    "name": "setCollectionMintMode",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "collectionNestingAndPermissions",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "properties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "sponsor",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionSponsorCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "uniqueCollectionType",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/fungibleDeprecated.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/fungibleDeprecated.json
@@ -0,0 +1,151 @@
+[
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newAdmin", "type": "address" }
+    ],
+    "name": "addCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "addToCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newOwner", "type": "address" }
+    ],
+    "name": "changeCollectionOwner",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "deleteCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "isOwnerOrAdmin",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "admin", "type": "address" }
+    ],
+    "name": "removeCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "removeFromCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingPermissions",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionPermissionField",
+            "name": "field",
+            "type": "uint8"
+          },
+          { "internalType": "bool", "name": "value", "type": "bool" }
+        ],
+        "internalType": "struct CollectionNestingPermission[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+        ],
+        "internalType": "struct CollectionNesting",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bool", "name": "enable", "type": "bool" },
+      {
+        "internalType": "address[]",
+        "name": "collections",
+        "type": "address[]"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/nativeFungible.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/nativeFungible.json
@@ -0,0 +1,201 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "spender",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "spender", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "spender", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      }
+    ],
+    "name": "balanceOfCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/nonFungible.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/nonFungible.json
@@ -0,0 +1,988 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "approved",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "operator",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "bool",
+        "name": "approved",
+        "type": "bool"
+      }
+    ],
+    "name": "ApprovalForAll",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "TokenChanged",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newAdmin",
+        "type": "tuple"
+      }
+    ],
+    "name": "addCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "addToCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "allowlistedCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "approved", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "approved",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "approveCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      }
+    ],
+    "name": "balanceOfCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burn",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burnFromCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newOwner",
+        "type": "tuple"
+      }
+    ],
+    "name": "changeCollectionOwnerCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionAdmins",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionLimits",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNesting",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionOwner",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "collectionProperties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "collectionProperty",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionSponsor",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "confirmCollectionSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "contractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "deleteCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "deleteProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "description",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "getApproved",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "hasCollectionPendingSponsor",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "operator", "type": "address" }
+    ],
+    "name": "isApprovedForAll",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "isOwnerOrAdminCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
+    "name": "mint",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          {
+            "components": [
+              { "internalType": "address", "name": "eth", "type": "address" },
+              { "internalType": "uint256", "name": "sub", "type": "uint256" }
+            ],
+            "internalType": "struct CrossAddress",
+            "name": "owner",
+            "type": "tuple"
+          },
+          {
+            "components": [
+              { "internalType": "string", "name": "key", "type": "string" },
+              { "internalType": "bytes", "name": "value", "type": "bytes" }
+            ],
+            "internalType": "struct Property[]",
+            "name": "properties",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct MintTokenData[]",
+        "name": "data",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulkCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "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" }
+    ],
+    "name": "mintWithTokenURI",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "nextTokenId",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "ownerOf",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "ownerOfCross",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "properties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "property",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "admin",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "removeCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeFromCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "safeTransferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "bytes", "name": "data", "type": "bytes" }
+    ],
+    "name": "safeTransferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "operator", "type": "address" },
+      { "internalType": "bool", "name": "approved", "type": "bool" }
+    ],
+    "name": "setApprovalForAll",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
+    "name": "setCollectionAccess",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit",
+        "name": "limit",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+    "name": "setCollectionMintMode",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "collectionNestingAndPermissions",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "properties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "sponsor",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionSponsorCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "properties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          {
+            "components": [
+              {
+                "internalType": "enum TokenPermissionField",
+                "name": "code",
+                "type": "uint8"
+              },
+              { "internalType": "bool", "name": "value", "type": "bool" }
+            ],
+            "internalType": "struct PropertyPermission[]",
+            "name": "permissions",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct TokenPropertyPermission[]",
+        "name": "permissions",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setTokenPropertyPermissions",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenOfOwnerByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "tokenPropertyPermissions",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          {
+            "components": [
+              {
+                "internalType": "enum TokenPermissionField",
+                "name": "code",
+                "type": "uint8"
+              },
+              { "internalType": "bool", "name": "value", "type": "bool" }
+            ],
+            "internalType": "struct PropertyPermission[]",
+            "name": "permissions",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct TokenPropertyPermission[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "tokenURI",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "uniqueCollectionType",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/nonFungibleDeprecated.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/nonFungibleDeprecated.json
@@ -0,0 +1,172 @@
+[
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newAdmin", "type": "address" }
+    ],
+    "name": "addCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "addToCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "deleteCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "isOwnerOrAdmin",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "admin", "type": "address" }
+    ],
+    "name": "removeCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "removeFromCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newOwner", "type": "address" }
+    ],
+    "name": "changeCollectionOwner",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "deleteProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingPermissions",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionPermissionField",
+            "name": "field",
+            "type": "uint8"
+          },
+          { "internalType": "bool", "name": "value", "type": "bool" }
+        ],
+        "internalType": "struct CollectionNestingPermission[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+        ],
+        "internalType": "struct CollectionNesting",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bool", "name": "enable", "type": "bool" },
+      {
+        "internalType": "address[]",
+        "name": "collections",
+        "type": "address[]"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/reFungible.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/reFungible.json
@@ -0,0 +1,995 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "approved",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "operator",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "bool",
+        "name": "approved",
+        "type": "bool"
+      }
+    ],
+    "name": "ApprovalForAll",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "TokenChanged",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "uint256",
+        "name": "tokenId",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newAdmin",
+        "type": "tuple"
+      }
+    ],
+    "name": "addCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "addToCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "allowlistedCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "approved", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      }
+    ],
+    "name": "balanceOfCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burn",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burnFromCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "newOwner",
+        "type": "tuple"
+      }
+    ],
+    "name": "changeCollectionOwnerCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionAdmins",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionLimits",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNesting",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionOwner",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "collectionProperties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "collectionProperty",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionSponsor",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "confirmCollectionSponsorship",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "contractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "deleteCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "deleteProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "description",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "getApproved",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "hasCollectionPendingSponsor",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "operator", "type": "address" }
+    ],
+    "name": "isApprovedForAll",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "isOwnerOrAdminCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
+    "name": "mint",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          {
+            "components": [
+              {
+                "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 OwnerPieces[]",
+            "name": "owners",
+            "type": "tuple[]"
+          },
+          {
+            "components": [
+              { "internalType": "string", "name": "key", "type": "string" },
+              { "internalType": "bytes", "name": "value", "type": "bytes" }
+            ],
+            "internalType": "struct Property[]",
+            "name": "properties",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct MintTokenData[]",
+        "name": "tokenProperties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulkCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "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" }
+    ],
+    "name": "mintWithTokenURI",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "nextTokenId",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "ownerOf",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "ownerOfCross",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "properties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "property",
+    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "admin",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeCollectionAdminCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "removeCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "user",
+        "type": "tuple"
+      }
+    ],
+    "name": "removeFromCollectionAllowListCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "safeTransferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "bytes", "name": "data", "type": "bytes" }
+    ],
+    "name": "safeTransferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "operator", "type": "address" },
+      { "internalType": "bool", "name": "approved", "type": "bool" }
+    ],
+    "name": "setApprovalForAll",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
+    "name": "setCollectionAccess",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionLimitField",
+            "name": "field",
+            "type": "uint8"
+          },
+          {
+            "components": [
+              { "internalType": "bool", "name": "status", "type": "bool" },
+              { "internalType": "uint256", "name": "value", "type": "uint256" }
+            ],
+            "internalType": "struct OptionUint256",
+            "name": "value",
+            "type": "tuple"
+          }
+        ],
+        "internalType": "struct CollectionLimit",
+        "name": "limit",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionLimit",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+    "name": "setCollectionMintMode",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          {
+            "internalType": "bool",
+            "name": "collection_admin",
+            "type": "bool"
+          },
+          {
+            "internalType": "address[]",
+            "name": "restricted",
+            "type": "address[]"
+          }
+        ],
+        "internalType": "struct CollectionNestingAndPermission",
+        "name": "collectionNestingAndPermissions",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "properties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setCollectionProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "sponsor",
+        "type": "tuple"
+      }
+    ],
+    "name": "setCollectionSponsorCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "properties",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setProperties",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          {
+            "components": [
+              {
+                "internalType": "enum TokenPermissionField",
+                "name": "code",
+                "type": "uint8"
+              },
+              { "internalType": "bool", "name": "value", "type": "bool" }
+            ],
+            "internalType": "struct PropertyPermission[]",
+            "name": "permissions",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct TokenPropertyPermission[]",
+        "name": "permissions",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "setTokenPropertyPermissions",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "token", "type": "uint256" }
+    ],
+    "name": "tokenContractAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "uint256", "name": "index", "type": "uint256" }
+    ],
+    "name": "tokenOfOwnerByIndex",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "tokenPropertyPermissions",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          {
+            "components": [
+              {
+                "internalType": "enum TokenPermissionField",
+                "name": "code",
+                "type": "uint8"
+              },
+              { "internalType": "bool", "name": "value", "type": "bool" }
+            ],
+            "internalType": "struct PropertyPermission[]",
+            "name": "permissions",
+            "type": "tuple[]"
+          }
+        ],
+        "internalType": "struct TokenPropertyPermission[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "tokenURI",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "uniqueCollectionType",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/reFungibleDeprecated.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/reFungibleDeprecated.json
@@ -0,0 +1,200 @@
+[
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newAdmin", "type": "address" }
+    ],
+    "name": "addCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "addToCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
+    "name": "deleteCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "isOwnerOrAdmin",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "admin", "type": "address" }
+    ],
+    "name": "removeCollectionAdmin",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "user", "type": "address" }
+    ],
+    "name": "removeFromCollectionAllowList",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setCollectionSponsor",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "newOwner", "type": "address" }
+    ],
+    "name": "changeCollectionOwner",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string", "name": "key", "type": "string" }
+    ],
+    "name": "deleteProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
+    ],
+    "name": "mintBulk",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      {
+        "components": [
+          { "internalType": "uint256", "name": "field_0", "type": "uint256" },
+          { "internalType": "string", "name": "field_1", "type": "string" }
+        ],
+        "internalType": "struct Tuple0[]",
+        "name": "tokens",
+        "type": "tuple[]"
+      }
+    ],
+    "name": "mintBulkWithTokenURI",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingPermissions",
+    "outputs": [
+      {
+        "components": [
+          {
+            "internalType": "enum CollectionPermissionField",
+            "name": "field",
+            "type": "uint8"
+          },
+          { "internalType": "bool", "name": "value", "type": "bool" }
+        ],
+        "internalType": "struct CollectionNestingPermission[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "collectionNestingRestrictedCollectionIds",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "bool", "name": "token_owner", "type": "bool" },
+          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
+        ],
+        "internalType": "struct CollectionNesting",
+        "name": "",
+        "type": "tuple"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bool", "name": "enable", "type": "bool" },
+      {
+        "internalType": "address[]",
+        "name": "collections",
+        "type": "address[]"
+      }
+    ],
+    "name": "setCollectionNesting",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/reFungibleToken.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/reFungibleToken.json
@@ -0,0 +1,286 @@
+[
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "owner",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "spender",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Approval",
+    "type": "event"
+  },
+  {
+    "anonymous": false,
+    "inputs": [
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "from",
+        "type": "address"
+      },
+      {
+        "indexed": true,
+        "internalType": "address",
+        "name": "to",
+        "type": "address"
+      },
+      {
+        "indexed": false,
+        "internalType": "uint256",
+        "name": "value",
+        "type": "uint256"
+      }
+    ],
+    "name": "Transfer",
+    "type": "event"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" },
+      { "internalType": "address", "name": "spender", "type": "address" }
+    ],
+    "name": "allowance",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "spender",
+        "type": "tuple"
+      }
+    ],
+    "name": "allowanceCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "spender", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approve",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "spender",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "approveCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "owner", "type": "address" }
+    ],
+    "name": "balanceOf",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "owner",
+        "type": "tuple"
+      }
+    ],
+    "name": "balanceOfCross",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "decimals",
+    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "name",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "parentToken",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "parentTokenId",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "repartition",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
+    ],
+    "name": "supportsInterface",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "symbol",
+    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
+    "name": "totalSupply",
+    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transfer",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "address", "name": "to", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "from",
+        "type": "tuple"
+      },
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct CrossAddress",
+        "name": "to",
+        "type": "tuple"
+      },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "transferFromCross",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/abi/reFungibleTokenDeprecated.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/abi/reFungibleTokenDeprecated.json
@@ -0,0 +1,12 @@
+[
+  {
+    "inputs": [
+      { "internalType": "address", "name": "from", "type": "address" },
+      { "internalType": "uint256", "name": "amount", "type": "uint256" }
+    ],
+    "name": "burnFrom",
+    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  }
+]
addedjs-packages/evm-abi/api/CollectionHelpers.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/CollectionHelpers.sol
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface CollectionHelpersEvents {
+	event CollectionCreated(address indexed owner, address indexed collectionId);
+	event CollectionDestroyed(address indexed collectionId);
+	event CollectionChanged(address indexed collectionId);
+}
+
+/// @title Contract, which allows users to operate with collections
+/// @dev the ERC-165 identifier for this interface is 0x94e5af0d
+interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
+	/// Create a collection
+	/// @return address Address of the newly created collection
+	/// @dev EVM selector for this function is: 0x72b5bea7,
+	///  or in textual repr: createCollection((string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],(address,uint256),uint8))
+	function createCollection(CreateCollectionData memory data) external payable returns (address);
+
+	/// Create an NFT collection
+	/// @param name Name of the collection
+	/// @param description Informative description of the collection
+	/// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
+	/// @return address Address of the newly created collection
+	/// @dev EVM selector for this function is: 0x844af658,
+	///  or in textual repr: createNFTCollection(string,string,string)
+	function createNFTCollection(
+		string memory name,
+		string memory description,
+		string memory tokenPrefix
+	) external payable returns (address);
+
+	// /// Create an NFT collection
+	// /// @param name Name of the collection
+	// /// @param description Informative description of the collection
+	// /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
+	// /// @return address Address of the newly created collection
+	// /// @dev EVM selector for this function is: 0xe34a6844,
+	// ///  or in textual repr: createNonfungibleCollection(string,string,string)
+	// function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) external payable returns (address);
+
+	/// @dev EVM selector for this function is: 0xab173450,
+	///  or in textual repr: createRFTCollection(string,string,string)
+	function createRFTCollection(
+		string memory name,
+		string memory description,
+		string memory tokenPrefix
+	) external payable returns (address);
+
+	/// @dev EVM selector for this function is: 0x7335b79f,
+	///  or in textual repr: createFTCollection(string,uint8,string,string)
+	function createFTCollection(
+		string memory name,
+		uint8 decimals,
+		string memory description,
+		string memory tokenPrefix
+	) external payable returns (address);
+
+	/// @dev EVM selector for this function is: 0x85624258,
+	///  or in textual repr: makeCollectionERC721MetadataCompatible(address,string)
+	function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;
+
+	/// @dev EVM selector for this function is: 0x564e321f,
+	///  or in textual repr: destroyCollection(address)
+	function destroyCollection(address collectionAddress) external;
+
+	/// Check if a collection exists
+	/// @param collectionAddress Address of the collection in question
+	/// @return bool Does the collection exist?
+	/// @dev EVM selector for this function is: 0xc3de1494,
+	///  or in textual repr: isCollectionExist(address)
+	function isCollectionExist(address collectionAddress) external view returns (bool);
+
+	/// @dev EVM selector for this function is: 0xd23a7ab1,
+	///  or in textual repr: collectionCreationFee()
+	function collectionCreationFee() external view returns (uint256);
+
+	/// Returns address of a collection.
+	/// @param collectionId  - CollectionId  of the collection
+	/// @return eth mirror address of the collection
+	/// @dev EVM selector for this function is: 0x2e716683,
+	///  or in textual repr: collectionAddress(uint32)
+	function collectionAddress(uint32 collectionId) external view returns (address);
+
+	/// Returns collectionId of a collection.
+	/// @param collectionAddress  - Eth address of the collection
+	/// @return collectionId of the collection
+	/// @dev EVM selector for this function is: 0xb5cb7498,
+	///  or in textual repr: collectionId(address)
+	function collectionId(address collectionAddress) external view returns (uint32);
+}
+
+/// Collection properties
+struct CreateCollectionData {
+	/// Collection name
+	string name;
+	/// Collection description
+	string description;
+	/// Token prefix
+	string token_prefix;
+	/// Token type (NFT, FT or RFT)
+	CollectionMode mode;
+	/// Fungible token precision
+	uint8 decimals;
+	/// Custom Properties
+	Property[] properties;
+	/// Permissions for token properties
+	TokenPropertyPermission[] token_property_permissions;
+	/// Collection admins
+	CrossAddress[] admin_list;
+	/// Nesting settings
+	CollectionNestingAndPermission nesting_settings;
+	/// Collection limits
+	CollectionLimitValue[] limits;
+	/// Collection sponsor
+	CrossAddress pending_sponsor;
+	/// Extra collection flags
+	CollectionFlags flags;
+}
+
+type CollectionFlags is uint8;
+
+library CollectionFlagsLib {
+	/// A collection of foreign assets
+	CollectionFlags constant foreignField = CollectionFlags.wrap(128);
+	/// Supports ERC721Metadata
+	CollectionFlags constant erc721metadataField = CollectionFlags.wrap(64);
+	/// External collections can't be managed using `unique` api
+	CollectionFlags constant externalField = CollectionFlags.wrap(1);
+
+	/// Reserved flags
+	function reservedField(uint8 value) public pure returns (CollectionFlags) {
+		require(value < 1 << 5, "out of bound value");
+		return CollectionFlags.wrap(value << 1);
+	}
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimitValue {
+	CollectionLimitField field;
+	uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+	/// How many tokens can a user have on one account.
+	AccountTokenOwnership,
+	/// How many bytes of data are available for sponsorship.
+	SponsoredDataSize,
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	SponsoredDataRateLimit,
+	/// How many tokens can be mined into this collection.
+	TokenLimit,
+	/// Timeouts for transfer sponsoring.
+	SponsorTransferTimeout,
+	/// Timeout for sponsoring an approval in passed blocks.
+	SponsorApproveTimeout,
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
+	OwnerCanTransfer,
+	/// Can the collection owner burn other people's tokens.
+	OwnerCanDestroy,
+	/// Is it possible to send tokens from this collection between users.
+	TransferEnabled
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+	/// Owner of token can nest tokens under it.
+	bool token_owner;
+	/// Admin of token collection can nest tokens under token.
+	bool collection_admin;
+	/// If set - only tokens from specified collections can be nested.
+	address[] restricted;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+	/// Token property key.
+	string key;
+	/// Token property permissions.
+	PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+	/// TokenPermission field.
+	TokenPermissionField code;
+	/// TokenPermission value.
+	bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	Mutable,
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	TokenOwner,
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	CollectionAdmin
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+	string key;
+	bytes value;
+}
+
+/// Type of tokens in collection
+enum CollectionMode {
+	/// Nonfungible
+	Nonfungible,
+	/// Fungible
+	Fungible,
+	/// Refungible
+	Refungible
+}
addedjs-packages/evm-abi/api/ContractHelpers.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/ContractHelpers.sol
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ContractHelpersEvents {
+	event ContractSponsorSet(address indexed contractAddress, address sponsor);
+	event ContractSponsorshipConfirmed(address indexed contractAddress, address sponsor);
+	event ContractSponsorRemoved(address indexed contractAddress);
+}
+
+/// @title Magic contract, which allows users to reconfigure other contracts
+/// @dev the ERC-165 identifier for this interface is 0x30afad04
+interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
+	/// Get user, which deployed specified contract
+	/// @dev May return zero address in case if contract is deployed
+	///  using uniquenetwork evm-migration pallet, or using other terms not
+	///  intended by pallet-evm
+	/// @dev Returns zero address if contract does not exists
+	/// @param contractAddress Contract to get owner of
+	/// @return address Owner of contract
+	/// @dev EVM selector for this function is: 0x5152b14c,
+	///  or in textual repr: contractOwner(address)
+	function contractOwner(address contractAddress) external view returns (address);
+
+	/// Set sponsor.
+	/// @param contractAddress Contract for which a sponsor is being established.
+	/// @param sponsor User address who set as pending sponsor.
+	/// @dev EVM selector for this function is: 0xf01fba93,
+	///  or in textual repr: setSponsor(address,address)
+	function setSponsor(address contractAddress, address sponsor) external;
+
+	/// Set contract as self sponsored.
+	///
+	/// @param contractAddress Contract for which a self sponsoring is being enabled.
+	/// @dev EVM selector for this function is: 0x89f7d9ae,
+	///  or in textual repr: selfSponsoredEnable(address)
+	function selfSponsoredEnable(address contractAddress) external;
+
+	/// Remove sponsor.
+	///
+	/// @param contractAddress Contract for which a sponsorship is being removed.
+	/// @dev EVM selector for this function is: 0xef784250,
+	///  or in textual repr: removeSponsor(address)
+	function removeSponsor(address contractAddress) external;
+
+	/// Confirm sponsorship.
+	///
+	/// @dev Caller must be same that set via [`setSponsor`].
+	///
+	/// @param contractAddress Сontract for which need to confirm sponsorship.
+	/// @dev EVM selector for this function is: 0xabc00001,
+	///  or in textual repr: confirmSponsorship(address)
+	function confirmSponsorship(address contractAddress) external;
+
+	/// Get current sponsor.
+	///
+	/// @param contractAddress The contract for which a sponsor is requested.
+	/// @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: 0x766c4f37,
+	///  or in textual repr: sponsor(address)
+	function sponsor(address contractAddress) external view returns (OptionCrossAddress memory);
+
+	/// Check tat contract has confirmed sponsor.
+	///
+	/// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
+	/// @return **true** if contract has confirmed sponsor.
+	/// @dev EVM selector for this function is: 0x97418603,
+	///  or in textual repr: hasSponsor(address)
+	function hasSponsor(address contractAddress) external view returns (bool);
+
+	/// Check tat contract has pending sponsor.
+	///
+	/// @param contractAddress The contract for which the presence of a pending sponsor is checked.
+	/// @return **true** if contract has pending sponsor.
+	/// @dev EVM selector for this function is: 0x39b9b242,
+	///  or in textual repr: hasPendingSponsor(address)
+	function hasPendingSponsor(address contractAddress) external view returns (bool);
+
+	/// @dev EVM selector for this function is: 0x6027dc61,
+	///  or in textual repr: sponsoringEnabled(address)
+	function sponsoringEnabled(address contractAddress) external view returns (bool);
+
+	/// @dev EVM selector for this function is: 0xfde8a560,
+	///  or in textual repr: setSponsoringMode(address,uint8)
+	function setSponsoringMode(address contractAddress, SponsoringModeT mode) external;
+
+	/// Get current contract sponsoring rate limit
+	/// @param contractAddress Contract to get sponsoring rate limit of
+	/// @return uint32 Amount of blocks between two sponsored transactions
+	/// @dev EVM selector for this function is: 0xf29694d8,
+	///  or in textual repr: sponsoringRateLimit(address)
+	function sponsoringRateLimit(address contractAddress) external view returns (uint32);
+
+	/// Set contract sponsoring rate limit
+	/// @dev Sponsoring rate limit - is a minimum amount of blocks that should
+	///  pass between two sponsored transactions
+	/// @param contractAddress Contract to change sponsoring rate limit of
+	/// @param rateLimit Target rate limit
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x77b6c908,
+	///  or in textual repr: setSponsoringRateLimit(address,uint32)
+	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) external;
+
+	/// Set contract sponsoring fee limit
+	/// @dev Sponsoring fee limit - is maximum fee that could be spent by
+	///  single transaction
+	/// @param contractAddress Contract to change sponsoring fee limit of
+	/// @param feeLimit Fee limit
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x03aed665,
+	///  or in textual repr: setSponsoringFeeLimit(address,uint256)
+	function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) external;
+
+	/// Get current contract sponsoring fee limit
+	/// @param contractAddress Contract to get sponsoring fee limit of
+	/// @return uint256 Maximum amount of fee that could be spent by single
+	///  transaction
+	/// @dev EVM selector for this function is: 0x75b73606,
+	///  or in textual repr: sponsoringFeeLimit(address)
+	function sponsoringFeeLimit(address contractAddress) external view returns (uint256);
+
+	/// Is specified user present in contract allow list
+	/// @dev Contract owner always implicitly included
+	/// @param contractAddress Contract to check allowlist of
+	/// @param user User to check
+	/// @return bool Is specified users exists in contract allowlist
+	/// @dev EVM selector for this function is: 0x5c658165,
+	///  or in textual repr: allowed(address,address)
+	function allowed(address contractAddress, address user) external view returns (bool);
+
+	/// Toggle user presence in contract allowlist
+	/// @param contractAddress Contract to change allowlist of
+	/// @param user Which user presence should be toggled
+	/// @param isAllowed `true` if user should be allowed to be sponsored
+	///  or call this contract, `false` otherwise
+	/// @dev Only contract owner can change this setting
+	/// @dev EVM selector for this function is: 0x4706cc1c,
+	///  or in textual repr: toggleAllowed(address,address,bool)
+	function toggleAllowed(
+		address contractAddress,
+		address user,
+		bool isAllowed
+	) external;
+
+	/// Is this contract has allowlist access enabled
+	/// @dev Allowlist always can have users, and it is used for two purposes:
+	///  in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
+	///  in case of allowlist access enabled, only users from allowlist may call this contract
+	/// @param contractAddress Contract to get allowlist access of
+	/// @return bool Is specified contract has allowlist access enabled
+	/// @dev EVM selector for this function is: 0xc772ef6c,
+	///  or in textual repr: allowlistEnabled(address)
+	function allowlistEnabled(address contractAddress) external view returns (bool);
+
+	/// Toggle contract allowlist access
+	/// @param contractAddress Contract to change allowlist access of
+	/// @param enabled Should allowlist access to be enabled?
+	/// @dev EVM selector for this function is: 0x36de20f5,
+	///  or in textual repr: toggleAllowlist(address,bool)
+	function toggleAllowlist(address contractAddress, bool enabled) external;
+}
+
+/// Available contract sponsoring modes
+enum SponsoringModeT {
+	/// Sponsoring is disabled
+	Disabled,
+	/// Only users from allowlist will be sponsored
+	Allowlisted,
+	/// All users will be sponsored
+	Generous
+}
+
+/// Optional value
+struct OptionCrossAddress {
+	/// Shows the status of accessibility of value
+	bool status;
+	/// Actual value if `status` is true
+	CrossAddress value;
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
addedjs-packages/evm-abi/api/UniqueFungible.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/UniqueFungible.sol
@@ -0,0 +1,510 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+	// /// Set collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @param value Propery value.
+	// /// @dev EVM selector for this function is: 0x2f073f66,
+	// ///  or in textual repr: setCollectionProperty(string,bytes)
+	// function setCollectionProperty(string memory key, bytes memory value) external;
+
+	/// Set collection properties.
+	///
+	/// @param properties Vector of properties key/value pair.
+	/// @dev EVM selector for this function is: 0x50b26b2a,
+	///  or in textual repr: setCollectionProperties((string,bytes)[])
+	function setCollectionProperties(Property[] memory properties) external;
+
+	// /// Delete collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x7b7debce,
+	// ///  or in textual repr: deleteCollectionProperty(string)
+	// function deleteCollectionProperty(string memory key) external;
+
+	/// Delete collection properties.
+	///
+	/// @param keys Properties keys.
+	/// @dev EVM selector for this function is: 0xee206ee3,
+	///  or in textual repr: deleteCollectionProperties(string[])
+	function deleteCollectionProperties(string[] memory keys) external;
+
+	/// Get collection property.
+	///
+	/// @dev Throws error if key not found.
+	///
+	/// @param key Property key.
+	/// @return bytes The property corresponding to the key.
+	/// @dev EVM selector for this function is: 0xcf24fd6d,
+	///  or in textual repr: collectionProperty(string)
+	function collectionProperty(string memory key) external view returns (bytes memory);
+
+	/// Get collection properties.
+	///
+	/// @param keys Properties keys. Empty keys for all propertyes.
+	/// @return Vector of properties key/value pairs.
+	/// @dev EVM selector for this function is: 0x285fb8e6,
+	///  or in textual repr: collectionProperties(string[])
+	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+	// /// Set the sponsor of the collection.
+	// ///
+	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	// ///
+	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	// /// @dev EVM selector for this function is: 0x7623402e,
+	// ///  or in textual repr: setCollectionSponsor(address)
+	// function setCollectionSponsor(address sponsor) external;
+
+	/// Set the sponsor of the collection.
+	///
+	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	///
+	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+	/// @dev EVM selector for this function is: 0x84a1d5a8,
+	///  or in textual repr: setCollectionSponsorCross((address,uint256))
+	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+	/// Whether there is a pending sponsor.
+	/// @dev EVM selector for this function is: 0x058ac185,
+	///  or in textual repr: hasCollectionPendingSponsor()
+	function hasCollectionPendingSponsor() external view returns (bool);
+
+	/// Collection sponsorship confirmation.
+	///
+	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	/// @dev EVM selector for this function is: 0x3c50e97a,
+	///  or in textual repr: confirmCollectionSponsorship()
+	function confirmCollectionSponsorship() external;
+
+	/// Remove collection sponsor.
+	/// @dev EVM selector for this function is: 0x6e0326a3,
+	///  or in textual repr: removeCollectionSponsor()
+	function removeCollectionSponsor() external;
+
+	/// Get current sponsor.
+	///
+	/// @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 (CrossAddress memory);
+
+	/// Get current collection limits.
+	///
+	/// @return Array of collection limits
+	/// @dev EVM selector for this function is: 0xf63bc572,
+	///  or in textual repr: collectionLimits()
+	function collectionLimits() external view returns (CollectionLimit[] memory);
+
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Some limit.
+	/// @dev EVM selector for this function is: 0x2316ee74,
+	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+	function setCollectionLimit(CollectionLimit memory limit) external;
+
+	/// Get contract address.
+	/// @dev EVM selector for this function is: 0xf6b4dfb4,
+	///  or in textual repr: contractAddress()
+	function contractAddress() external view returns (address);
+
+	/// Add collection admin.
+	/// @param newAdmin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x859aa7d6,
+	///  or in textual repr: addCollectionAdminCross((address,uint256))
+	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+	/// Remove collection admin.
+	/// @param admin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x6c0cd173,
+	///  or in textual repr: removeCollectionAdminCross((address,uint256))
+	function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+	// /// Add collection admin.
+	// /// @param newAdmin Address of the added administrator.
+	// /// @dev EVM selector for this function is: 0x92e462c7,
+	// ///  or in textual repr: addCollectionAdmin(address)
+	// function addCollectionAdmin(address newAdmin) external;
+
+	// /// Remove collection admin.
+	// ///
+	// /// @param admin Address of the removed administrator.
+	// /// @dev EVM selector for this function is: 0xfafd7b42,
+	// ///  or in textual repr: removeCollectionAdmin(address)
+	// function removeCollectionAdmin(address admin) external;
+
+	/// @dev EVM selector for this function is: 0x0b9f3890,
+	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
+	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	// /// @dev EVM selector for this function is: 0x112d4586,
+	// ///  or in textual repr: setCollectionNesting(bool)
+	// function setCollectionNesting(bool enable) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// /// @param collections Addresses of collections that will be available for nesting.
+	// /// @dev EVM selector for this function is: 0x64872396,
+	// ///  or in textual repr: setCollectionNesting(bool,address[])
+	// function setCollectionNesting(bool enable, address[] memory collections) external;
+
+	/// @dev EVM selector for this function is: 0x92c660a8,
+	///  or in textual repr: collectionNesting()
+	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+	// /// Returns nesting for a collection
+	// /// @dev EVM selector for this function is: 0x22d25bfe,
+	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+	// /// Returns permissions for a collection
+	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
+	// ///  or in textual repr: collectionNestingPermissions()
+	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+	/// Set the collection access method.
+	/// @param mode Access mode
+	/// @dev EVM selector for this function is: 0x41835d4c,
+	///  or in textual repr: setCollectionAccess(uint8)
+	function setCollectionAccess(AccessMode mode) external;
+
+	/// Checks that user allowed to operate with collection.
+	///
+	/// @param user User address to check.
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+	// /// Add the user to the allowed list.
+	// ///
+	// /// @param user Address of a trusted user.
+	// /// @dev EVM selector for this function is: 0x67844fe6,
+	// ///  or in textual repr: addToCollectionAllowList(address)
+	// function addToCollectionAllowList(address user) external;
+
+	/// Add user to allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0xa0184a3a,
+	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
+	function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+	// /// Remove the user from the allowed list.
+	// ///
+	// /// @param user Address of a removed user.
+	// /// @dev EVM selector for this function is: 0x85c51acb,
+	// ///  or in textual repr: removeFromCollectionAllowList(address)
+	// function removeFromCollectionAllowList(address user) external;
+
+	/// Remove user from allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0x09ba452a,
+	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+	/// Switch permission for minting.
+	///
+	/// @param mode Enable if "true".
+	/// @dev EVM selector for this function is: 0x00018e84,
+	///  or in textual repr: setCollectionMintMode(bool)
+	function setCollectionMintMode(bool mode) external;
+
+	// /// Check that account is the owner or admin of the collection
+	// ///
+	// /// @param user account to verify
+	// /// @return "true" if account is the owner or admin
+	// /// @dev EVM selector for this function is: 0x9811b0c7,
+	// ///  or in textual repr: isOwnerOrAdmin(address)
+	// function isOwnerOrAdmin(address user) external view returns (bool);
+
+	/// Check that account is the owner or admin of the collection
+	///
+	/// @param user User cross account to verify
+	/// @return "true" if account is the owner or admin
+	/// @dev EVM selector for this function is: 0x3e75a905,
+	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
+	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+	/// Returns collection type
+	///
+	/// @return `Fungible` or `NFT` or `ReFungible`
+	/// @dev EVM selector for this function is: 0xd34b55b8,
+	///  or in textual repr: uniqueCollectionType()
+	function uniqueCollectionType() external view returns (string memory);
+
+	/// Get collection owner.
+	///
+	/// @return Tuble with sponsor address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0xdf727d3b,
+	///  or in textual repr: collectionOwner()
+	function collectionOwner() external view returns (CrossAddress memory);
+
+	// /// Changes collection owner to another account
+	// ///
+	// /// @dev Owner can be changed only by current owner
+	// /// @param newOwner new owner account
+	// /// @dev EVM selector for this function is: 0x4f53e226,
+	// ///  or in textual repr: changeCollectionOwner(address)
+	// function changeCollectionOwner(address newOwner) external;
+
+	/// Get collection administrators
+	///
+	/// @return Vector of tuples with admins address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0x5813216b,
+	///  or in textual repr: collectionAdmins()
+	function collectionAdmins() external view returns (CrossAddress[] memory);
+
+	/// Changes collection owner to another account
+	///
+	/// @dev Owner can be changed only by current owner
+	/// @param newOwner new owner cross account
+	/// @dev EVM selector for this function is: 0x6496c497,
+	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
+	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+	CollectionPermissionField field;
+	bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+	/// Owner of token can nest tokens under it.
+	TokenOwner,
+	/// Admin of token collection can nest tokens under token.
+	CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+	bool token_owner;
+	uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+	/// Owner of token can nest tokens under it.
+	bool token_owner;
+	/// Admin of token collection can nest tokens under token.
+	bool collection_admin;
+	/// If set - only tokens from specified collections can be nested.
+	address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+	CollectionLimitField field;
+	OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+	/// Shows the status of accessibility of value
+	bool status;
+	/// Actual value if `status` is true
+	uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+	/// How many tokens can a user have on one account.
+	AccountTokenOwnership,
+	/// How many bytes of data are available for sponsorship.
+	SponsoredDataSize,
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	SponsoredDataRateLimit,
+	/// How many tokens can be mined into this collection.
+	TokenLimit,
+	/// Timeouts for transfer sponsoring.
+	SponsorTransferTimeout,
+	/// Timeout for sponsoring an approval in passed blocks.
+	SponsorApproveTimeout,
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
+	OwnerCanTransfer,
+	/// Can the collection owner burn other people's tokens.
+	OwnerCanDestroy,
+	/// Is it possible to send tokens from this collection between users.
+	TransferEnabled
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+	string key;
+	bytes value;
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x69d14d3e
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
+	/// @param owner crossAddress The address which owns the funds.
+	/// @param spender crossAddress The address which will spend the funds.
+	/// @return A uint256 specifying the amount of tokens still available for the spender.
+	/// @dev EVM selector for this function is: 0xe0af4bd7,
+	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
+	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
+
+	/// @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(CrossAddress 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(CrossAddress memory spender, uint256 amount) external returns (bool);
+
+	// /// Burn tokens from account
+	// /// @dev Function that burns an `amount` of the tokens of a given account,
+	// /// deducting from the sender's allowance for said account.
+	// /// @param from The account whose tokens will be burnt.
+	// /// @param amount The amount that will be burnt.
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 amount) external returns (bool);
+
+	/// Burn tokens from account
+	/// @dev Function that burns an `amount` of the tokens of a given account,
+	/// deducting from the sender's allowance for said account.
+	/// @param from The account whose tokens will be burnt.
+	/// @param amount The amount that will be burnt.
+	/// @dev EVM selector for this function is: 0xbb2f5a58,
+	///  or in textual repr: burnFromCross((address,uint256),uint256)
+	function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
+
+	/// Mint tokens for multiple accounts.
+	/// @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(AmountForAddress[] memory amounts) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0x2ada85ff,
+	///  or in textual repr: transferCross((address,uint256),uint256)
+	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		CrossAddress memory from,
+		CrossAddress memory to,
+		uint256 amount
+	) external returns (bool);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
+
+	/// @notice Balance of account
+	/// @param owner An cross address for whom to query the balance
+	/// @return The number of fingibles owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0xec069398,
+	///  or in textual repr: balanceOfCross((address,uint256))
+	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+}
+
+struct AmountForAddress {
+	address to;
+	uint256 amount;
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x40c10f19
+interface ERC20Mintable is Dummy, ERC165 {
+	/// Mint tokens for `to` account.
+	/// @param to account that will receive minted tokens
+	/// @param amount amount of tokens to mint
+	/// @dev EVM selector for this function is: 0x40c10f19,
+	///  or in textual repr: mint(address,uint256)
+	function mint(address to, uint256 amount) external returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+	event Transfer(address indexed from, address indexed to, uint256 value);
+	event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+	/// @dev EVM selector for this function is: 0x06fdde03,
+	///  or in textual repr: name()
+	function name() external view returns (string memory);
+
+	/// @dev EVM selector for this function is: 0x95d89b41,
+	///  or in textual repr: symbol()
+	function symbol() external view returns (string memory);
+
+	/// @dev EVM selector for this function is: 0x18160ddd,
+	///  or in textual repr: totalSupply()
+	function totalSupply() external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0x313ce567,
+	///  or in textual repr: decimals()
+	function decimals() external view returns (uint8);
+
+	/// @dev EVM selector for this function is: 0x70a08231,
+	///  or in textual repr: balanceOf(address)
+	function balanceOf(address owner) external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0xa9059cbb,
+	///  or in textual repr: transfer(address,uint256)
+	function transfer(address to, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0x23b872dd,
+	///  or in textual repr: transferFrom(address,address,uint256)
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0x095ea7b3,
+	///  or in textual repr: approve(address,uint256)
+	function approve(address spender, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0xdd62ed3e,
+	///  or in textual repr: allowance(address,address)
+	function allowance(address owner, address spender) external view returns (uint256);
+}
+
+interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
addedjs-packages/evm-abi/api/UniqueNFT.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/UniqueNFT.sol
@@ -0,0 +1,855 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC721TokenEvent {
+	event TokenChanged(uint256 indexed tokenId);
+}
+
+/// @title A contract that allows to set and delete token properties and change token property permissions.
+/// @dev the ERC-165 identifier for this interface is 0xde0695c2
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
+	// /// @notice Set permissions for token property.
+	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	// /// @param key Property key.
+	// /// @param isMutable Permission to mutate property.
+	// /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
+	// /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+	// /// @dev EVM selector for this function is: 0x222d97fa,
+	// ///  or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
+	// function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
+
+	/// @notice Set permissions for token property.
+	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	/// @param permissions Permissions for keys.
+	/// @dev EVM selector for this function is: 0xbd92983a,
+	///  or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
+	function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
+
+	/// @notice Get permissions for token properties.
+	/// @dev EVM selector for this function is: 0xf23d7790,
+	///  or in textual repr: tokenPropertyPermissions()
+	function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
+
+	// /// @notice Set token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @param value Property value.
+	// /// @dev EVM selector for this function is: 0x1752d67b,
+	// ///  or in textual repr: setProperty(uint256,string,bytes)
+	// function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
+
+	/// @notice Set token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param properties settable properties
+	/// @dev EVM selector for this function is: 0x14ed3a6e,
+	///  or in textual repr: setProperties(uint256,(string,bytes)[])
+	function setProperties(uint256 tokenId, Property[] memory properties) external;
+
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) external;
+
+	/// @notice Delete token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) external;
+
+	/// @notice Get token property value.
+	/// @dev Throws error if key not found
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @return Property value bytes
+	/// @dev EVM selector for this function is: 0x7228c327,
+	///  or in textual repr: property(uint256,string)
+	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+	string key;
+	bytes value;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+	/// Token property key.
+	string key;
+	/// Token property permissions.
+	PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+	/// TokenPermission field.
+	TokenPermissionField code;
+	/// TokenPermission value.
+	bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	Mutable,
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	TokenOwner,
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	CollectionAdmin
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+	// /// Set collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @param value Propery value.
+	// /// @dev EVM selector for this function is: 0x2f073f66,
+	// ///  or in textual repr: setCollectionProperty(string,bytes)
+	// function setCollectionProperty(string memory key, bytes memory value) external;
+
+	/// Set collection properties.
+	///
+	/// @param properties Vector of properties key/value pair.
+	/// @dev EVM selector for this function is: 0x50b26b2a,
+	///  or in textual repr: setCollectionProperties((string,bytes)[])
+	function setCollectionProperties(Property[] memory properties) external;
+
+	// /// Delete collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x7b7debce,
+	// ///  or in textual repr: deleteCollectionProperty(string)
+	// function deleteCollectionProperty(string memory key) external;
+
+	/// Delete collection properties.
+	///
+	/// @param keys Properties keys.
+	/// @dev EVM selector for this function is: 0xee206ee3,
+	///  or in textual repr: deleteCollectionProperties(string[])
+	function deleteCollectionProperties(string[] memory keys) external;
+
+	/// Get collection property.
+	///
+	/// @dev Throws error if key not found.
+	///
+	/// @param key Property key.
+	/// @return bytes The property corresponding to the key.
+	/// @dev EVM selector for this function is: 0xcf24fd6d,
+	///  or in textual repr: collectionProperty(string)
+	function collectionProperty(string memory key) external view returns (bytes memory);
+
+	/// Get collection properties.
+	///
+	/// @param keys Properties keys. Empty keys for all propertyes.
+	/// @return Vector of properties key/value pairs.
+	/// @dev EVM selector for this function is: 0x285fb8e6,
+	///  or in textual repr: collectionProperties(string[])
+	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+	// /// Set the sponsor of the collection.
+	// ///
+	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	// ///
+	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	// /// @dev EVM selector for this function is: 0x7623402e,
+	// ///  or in textual repr: setCollectionSponsor(address)
+	// function setCollectionSponsor(address sponsor) external;
+
+	/// Set the sponsor of the collection.
+	///
+	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	///
+	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+	/// @dev EVM selector for this function is: 0x84a1d5a8,
+	///  or in textual repr: setCollectionSponsorCross((address,uint256))
+	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+	/// Whether there is a pending sponsor.
+	/// @dev EVM selector for this function is: 0x058ac185,
+	///  or in textual repr: hasCollectionPendingSponsor()
+	function hasCollectionPendingSponsor() external view returns (bool);
+
+	/// Collection sponsorship confirmation.
+	///
+	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	/// @dev EVM selector for this function is: 0x3c50e97a,
+	///  or in textual repr: confirmCollectionSponsorship()
+	function confirmCollectionSponsorship() external;
+
+	/// Remove collection sponsor.
+	/// @dev EVM selector for this function is: 0x6e0326a3,
+	///  or in textual repr: removeCollectionSponsor()
+	function removeCollectionSponsor() external;
+
+	/// Get current sponsor.
+	///
+	/// @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 (CrossAddress memory);
+
+	/// Get current collection limits.
+	///
+	/// @return Array of collection limits
+	/// @dev EVM selector for this function is: 0xf63bc572,
+	///  or in textual repr: collectionLimits()
+	function collectionLimits() external view returns (CollectionLimit[] memory);
+
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Some limit.
+	/// @dev EVM selector for this function is: 0x2316ee74,
+	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+	function setCollectionLimit(CollectionLimit memory limit) external;
+
+	/// Get contract address.
+	/// @dev EVM selector for this function is: 0xf6b4dfb4,
+	///  or in textual repr: contractAddress()
+	function contractAddress() external view returns (address);
+
+	/// Add collection admin.
+	/// @param newAdmin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x859aa7d6,
+	///  or in textual repr: addCollectionAdminCross((address,uint256))
+	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+	/// Remove collection admin.
+	/// @param admin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x6c0cd173,
+	///  or in textual repr: removeCollectionAdminCross((address,uint256))
+	function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+	// /// Add collection admin.
+	// /// @param newAdmin Address of the added administrator.
+	// /// @dev EVM selector for this function is: 0x92e462c7,
+	// ///  or in textual repr: addCollectionAdmin(address)
+	// function addCollectionAdmin(address newAdmin) external;
+
+	// /// Remove collection admin.
+	// ///
+	// /// @param admin Address of the removed administrator.
+	// /// @dev EVM selector for this function is: 0xfafd7b42,
+	// ///  or in textual repr: removeCollectionAdmin(address)
+	// function removeCollectionAdmin(address admin) external;
+
+	/// @dev EVM selector for this function is: 0x0b9f3890,
+	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
+	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	// /// @dev EVM selector for this function is: 0x112d4586,
+	// ///  or in textual repr: setCollectionNesting(bool)
+	// function setCollectionNesting(bool enable) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// /// @param collections Addresses of collections that will be available for nesting.
+	// /// @dev EVM selector for this function is: 0x64872396,
+	// ///  or in textual repr: setCollectionNesting(bool,address[])
+	// function setCollectionNesting(bool enable, address[] memory collections) external;
+
+	/// @dev EVM selector for this function is: 0x92c660a8,
+	///  or in textual repr: collectionNesting()
+	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+	// /// Returns nesting for a collection
+	// /// @dev EVM selector for this function is: 0x22d25bfe,
+	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+	// /// Returns permissions for a collection
+	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
+	// ///  or in textual repr: collectionNestingPermissions()
+	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+	/// Set the collection access method.
+	/// @param mode Access mode
+	/// @dev EVM selector for this function is: 0x41835d4c,
+	///  or in textual repr: setCollectionAccess(uint8)
+	function setCollectionAccess(AccessMode mode) external;
+
+	/// Checks that user allowed to operate with collection.
+	///
+	/// @param user User address to check.
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+	// /// Add the user to the allowed list.
+	// ///
+	// /// @param user Address of a trusted user.
+	// /// @dev EVM selector for this function is: 0x67844fe6,
+	// ///  or in textual repr: addToCollectionAllowList(address)
+	// function addToCollectionAllowList(address user) external;
+
+	/// Add user to allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0xa0184a3a,
+	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
+	function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+	// /// Remove the user from the allowed list.
+	// ///
+	// /// @param user Address of a removed user.
+	// /// @dev EVM selector for this function is: 0x85c51acb,
+	// ///  or in textual repr: removeFromCollectionAllowList(address)
+	// function removeFromCollectionAllowList(address user) external;
+
+	/// Remove user from allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0x09ba452a,
+	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+	/// Switch permission for minting.
+	///
+	/// @param mode Enable if "true".
+	/// @dev EVM selector for this function is: 0x00018e84,
+	///  or in textual repr: setCollectionMintMode(bool)
+	function setCollectionMintMode(bool mode) external;
+
+	// /// Check that account is the owner or admin of the collection
+	// ///
+	// /// @param user account to verify
+	// /// @return "true" if account is the owner or admin
+	// /// @dev EVM selector for this function is: 0x9811b0c7,
+	// ///  or in textual repr: isOwnerOrAdmin(address)
+	// function isOwnerOrAdmin(address user) external view returns (bool);
+
+	/// Check that account is the owner or admin of the collection
+	///
+	/// @param user User cross account to verify
+	/// @return "true" if account is the owner or admin
+	/// @dev EVM selector for this function is: 0x3e75a905,
+	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
+	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+	/// Returns collection type
+	///
+	/// @return `Fungible` or `NFT` or `ReFungible`
+	/// @dev EVM selector for this function is: 0xd34b55b8,
+	///  or in textual repr: uniqueCollectionType()
+	function uniqueCollectionType() external view returns (string memory);
+
+	/// Get collection owner.
+	///
+	/// @return Tuble with sponsor address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0xdf727d3b,
+	///  or in textual repr: collectionOwner()
+	function collectionOwner() external view returns (CrossAddress memory);
+
+	// /// Changes collection owner to another account
+	// ///
+	// /// @dev Owner can be changed only by current owner
+	// /// @param newOwner new owner account
+	// /// @dev EVM selector for this function is: 0x4f53e226,
+	// ///  or in textual repr: changeCollectionOwner(address)
+	// function changeCollectionOwner(address newOwner) external;
+
+	/// Get collection administrators
+	///
+	/// @return Vector of tuples with admins address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0x5813216b,
+	///  or in textual repr: collectionAdmins()
+	function collectionAdmins() external view returns (CrossAddress[] memory);
+
+	/// Changes collection owner to another account
+	///
+	/// @dev Owner can be changed only by current owner
+	/// @param newOwner new owner cross account
+	/// @dev EVM selector for this function is: 0x6496c497,
+	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
+	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+	CollectionPermissionField field;
+	bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+	/// Owner of token can nest tokens under it.
+	TokenOwner,
+	/// Admin of token collection can nest tokens under token.
+	CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+	bool token_owner;
+	uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+	/// Owner of token can nest tokens under it.
+	bool token_owner;
+	/// Admin of token collection can nest tokens under token.
+	bool collection_admin;
+	/// If set - only tokens from specified collections can be nested.
+	address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+	CollectionLimitField field;
+	OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+	/// Shows the status of accessibility of value
+	bool status;
+	/// Actual value if `status` is true
+	uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+	/// How many tokens can a user have on one account.
+	AccountTokenOwnership,
+	/// How many bytes of data are available for sponsorship.
+	SponsoredDataSize,
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	SponsoredDataRateLimit,
+	/// How many tokens can be mined into this collection.
+	TokenLimit,
+	/// Timeouts for transfer sponsoring.
+	SponsorTransferTimeout,
+	/// Timeout for sponsoring an approval in passed blocks.
+	SponsorApproveTimeout,
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
+	OwnerCanTransfer,
+	/// Can the collection owner burn other people's tokens.
+	OwnerCanDestroy,
+	/// Is it possible to send tokens from this collection between users.
+	TransferEnabled
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
+interface ERC721Metadata is Dummy, ERC165 {
+	// /// @notice A descriptive name for a collection of NFTs in this contract
+	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+	// /// @dev EVM selector for this function is: 0x06fdde03,
+	// ///  or in textual repr: name()
+	// function name() external view returns (string memory);
+
+	// /// @notice An abbreviated name for NFTs in this contract
+	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+	// /// @dev EVM selector for this function is: 0x95d89b41,
+	// ///  or in textual repr: symbol()
+	// function symbol() external view returns (string memory);
+
+	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	///
+	/// @dev If the token has a `url` property and it is not empty, it is returned.
+	///  Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
+	///  If the collection property `baseURI` is empty or absent, return "" (empty string)
+	///  otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
+	///  otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
+	///
+	/// @return token's const_metadata
+	/// @dev EVM selector for this function is: 0xc87b56dd,
+	///  or in textual repr: tokenURI(uint256)
+	function tokenURI(uint256 tokenId) external view returns (string memory);
+}
+
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
+/// @dev the ERC-165 identifier for this interface is 0x42966c68
+interface ERC721Burnable is Dummy, ERC165 {
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param tokenId The NFT to approve
+	/// @dev EVM selector for this function is: 0x42966c68,
+	///  or in textual repr: burn(uint256)
+	function burn(uint256 tokenId) external;
+}
+
+/// @title ERC721 minting logic.
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
+	/// @notice Function to mint a token.
+	/// @param to The new owner
+	/// @return uint256 The id of the newly minted token
+	/// @dev EVM selector for this function is: 0x6a627842,
+	///  or in textual repr: mint(address)
+	function mint(address to) external returns (uint256);
+
+	// /// @notice Function to mint a token.
+	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
+	// ///  unlike standard, you can't specify it manually
+	// /// @param to The new owner
+	// /// @param tokenId ID of the minted NFT
+	// /// @dev EVM selector for this function is: 0x40c10f19,
+	// ///  or in textual repr: mint(address,uint256)
+	// function mint(address to, uint256 tokenId) external returns (bool);
+
+	/// @notice Function to mint token with the given tokenUri.
+	/// @param to The new owner
+	/// @param tokenUri Token URI that would be stored in the NFT properties
+	/// @return uint256 The id of the newly minted token
+	/// @dev EVM selector for this function is: 0x45c17782,
+	///  or in textual repr: mintWithTokenURI(address,string)
+	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
+	// /// @notice Function to mint token with the given tokenUri.
+	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
+	// ///  unlike standard, you can't specify it manually
+	// /// @param to The new owner
+	// /// @param tokenId ID of the minted NFT
+	// /// @param tokenUri Token URI that would be stored in the NFT properties
+	// /// @dev EVM selector for this function is: 0x50bb4e7f,
+	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
+	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
+
+}
+
+/// @title Unique extensions for ERC721.
+/// @dev the ERC-165 identifier for this interface is 0x9b397d16
+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,
+	///  or in textual repr: name()
+	function name() external view returns (string memory);
+
+	/// @notice An abbreviated name for NFTs in this contract
+	/// @dev EVM selector for this function is: 0x95d89b41,
+	///  or in textual repr: symbol()
+	function symbol() external view returns (string memory);
+
+	/// @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);
+
+	// /// Returns the owner (in cross format) of the token.
+	// ///
+	// /// @param tokenId Id for the token.
+	// /// @dev EVM selector for this function is: 0x2b29dace,
+	// ///  or in textual repr: crossOwnerOf(uint256)
+	// function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
+
+	/// Returns the owner (in cross format) of the token.
+	///
+	/// @param tokenId Id for the token.
+	/// @dev EVM selector for this function is: 0xcaa3a4d0,
+	///  or in textual repr: ownerOfCross(uint256)
+	function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
+
+	/// @notice Count all NFTs assigned to an owner
+	/// @param owner An cross address for whom to query the balance
+	/// @return The number of NFTs owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0xec069398,
+	///  or in textual repr: balanceOfCross((address,uint256))
+	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+	/// Returns the token properties.
+	///
+	/// @param tokenId Id for the token.
+	/// @param keys Properties keys. Empty keys for all propertyes.
+	/// @return Vector of properties key/value pairs.
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+
+	/// @notice Set or reaffirm the approved address for an NFT
+	/// @dev The zero address indicates there is no approved address.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param approved The new substrate address approved NFT controller
+	/// @param tokenId The NFT to approve
+	/// @dev EVM selector for this function is: 0x0ecd0ab0,
+	///  or in textual repr: approveCross((address,uint256),uint256)
+	function approveCross(CrossAddress memory approved, uint256 tokenId) external;
+
+	/// @notice Transfer ownership of an NFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0xa9059cbb,
+	///  or in textual repr: transfer(address,uint256)
+	function transfer(address to, uint256 tokenId) external;
+
+	/// @notice Transfer ownership of an NFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0x2ada85ff,
+	///  or in textual repr: transferCross((address,uint256),uint256)
+	function transferCross(CrossAddress memory to, uint256 tokenId) external;
+
+	/// @notice Transfer ownership of an NFT from cross account address to cross account address
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from Cross acccount address of current owner
+	/// @param to Cross acccount address of new owner
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		CrossAddress memory from,
+		CrossAddress memory to,
+		uint256 tokenId
+	) external;
+
+	// /// @notice Burns a specific ERC721 token.
+	// /// @dev Throws unless `msg.sender` is the current owner or an authorized
+	// ///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	// ///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	// /// @param from The current owner of the NFT
+	// /// @param tokenId The NFT to transfer
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 tokenId) external;
+
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0xbb2f5a58,
+	///  or in textual repr: burnFromCross((address,uint256),uint256)
+	function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
+
+	/// @notice Returns next free NFT ID.
+	/// @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
+	// /// @param to The new owner
+	// /// @param tokenIds IDs of the minted NFTs
+	// /// @dev EVM selector for this function is: 0x44a9945e,
+	// ///  or in textual repr: mintBulk(address,uint256[])
+	// function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
+
+	/// @notice Function to mint a token.
+	/// @param data Array of pairs of token owner and token's properties for minted token
+	/// @dev EVM selector for this function is: 0xab427b0c,
+	///  or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[])
+	function mintBulkCross(MintTokenData[] memory data) external returns (bool);
+
+	// /// @notice Function to mint multiple tokens with the given tokenUris.
+	// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	// ///  numbers and first number should be obtained with `nextTokenId` method
+	// /// @param to The new owner
+	// /// @param tokens array of pairs of token ID and token URI for minted tokens
+	// /// @dev EVM selector for this function is: 0x36543006,
+	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
+	// function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
+
+	/// @notice Function to mint a 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(CrossAddress memory to, Property[] memory properties) external returns (uint256);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
+}
+
+/// Data for creation token with uri.
+struct TokenUri {
+	/// Id of new token.
+	uint256 id;
+	/// Uri of new token.
+	string uri;
+}
+
+/// Token minting parameters
+struct MintTokenData {
+	/// Minted token owner
+	CrossAddress owner;
+	/// Minted token properties
+	Property[] properties;
+}
+
+/// @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
+interface ERC721Enumerable is Dummy, ERC165 {
+	/// @notice Enumerate valid NFTs
+	/// @param index A counter less than `totalSupply()`
+	/// @return The token identifier for the `index`th NFT,
+	///  (sort order not specified)
+	/// @dev EVM selector for this function is: 0x4f6ccce7,
+	///  or in textual repr: tokenByIndex(uint256)
+	function tokenByIndex(uint256 index) external view returns (uint256);
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0x2f745c59,
+	///  or in textual repr: tokenOfOwnerByIndex(address,uint256)
+	function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+	/// @notice Count NFTs tracked by this contract
+	/// @return A count of valid NFTs tracked by this contract, where each one of
+	///  them has an assigned and queryable owner not equal to the zero address
+	/// @dev EVM selector for this function is: 0x18160ddd,
+	///  or in textual repr: totalSupply()
+	function totalSupply() external view returns (uint256);
+}
+
+/// @dev inlined interface
+interface ERC721Events {
+	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+}
+
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
+/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+interface ERC721 is Dummy, ERC165, ERC721Events {
+	/// @notice Count all NFTs assigned to an owner
+	/// @dev NFTs assigned to the zero address are considered invalid, and this
+	///  function throws for queries about the zero address.
+	/// @param owner An address for whom to query the balance
+	/// @return The number of NFTs owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0x70a08231,
+	///  or in textual repr: balanceOf(address)
+	function balanceOf(address owner) external view returns (uint256);
+
+	/// @notice Find the owner of an NFT
+	/// @dev NFTs assigned to zero address are considered invalid, and queries
+	///  about them do throw.
+	/// @param tokenId The identifier for an NFT
+	/// @return The address of the owner of the NFT
+	/// @dev EVM selector for this function is: 0x6352211e,
+	///  or in textual repr: ownerOf(uint256)
+	function ownerOf(uint256 tokenId) external view returns (address);
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0xb88d4fde,
+	///  or in textual repr: safeTransferFrom(address,address,uint256,bytes)
+	function safeTransferFrom(
+		address from,
+		address to,
+		uint256 tokenId,
+		bytes memory data
+	) external;
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0x42842e0e,
+	///  or in textual repr: safeTransferFrom(address,address,uint256)
+	function safeTransferFrom(
+		address from,
+		address to,
+		uint256 tokenId
+	) external;
+
+	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
+	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	///  THEY MAY BE PERMANENTLY LOST
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this NFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
+	/// @param from The current owner of the NFT
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0x23b872dd,
+	///  or in textual repr: transferFrom(address,address,uint256)
+	function transferFrom(
+		address from,
+		address to,
+		uint256 tokenId
+	) external;
+
+	/// @notice Set or reaffirm the approved address for an NFT
+	/// @dev The zero address indicates there is no approved address.
+	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param approved The new approved NFT controller
+	/// @param tokenId The NFT to approve
+	/// @dev EVM selector for this function is: 0x095ea7b3,
+	///  or in textual repr: approve(address,uint256)
+	function approve(address approved, uint256 tokenId) external;
+
+	/// @notice Sets or unsets the approval of a given operator.
+	/// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
+	/// @param operator Operator
+	/// @param approved Should operator status be granted or revoked?
+	/// @dev EVM selector for this function is: 0xa22cb465,
+	///  or in textual repr: setApprovalForAll(address,bool)
+	function setApprovalForAll(address operator, bool approved) external;
+
+	/// @notice Get the approved address for a single NFT
+	/// @dev Throws if `tokenId` is not a valid NFT
+	/// @param tokenId The NFT to find the approved address for
+	/// @return The approved address for this NFT, or the zero address if there is none
+	/// @dev EVM selector for this function is: 0x081812fc,
+	///  or in textual repr: getApproved(uint256)
+	function getApproved(uint256 tokenId) external view returns (address);
+
+	/// @notice Tells whether the given `owner` approves the `operator`.
+	/// @dev EVM selector for this function is: 0xe985e9c5,
+	///  or in textual repr: isApprovedForAll(address,address)
+	function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
+
+interface UniqueNFT is
+	Dummy,
+	ERC165,
+	ERC721,
+	ERC721Enumerable,
+	ERC721UniqueExtensions,
+	ERC721UniqueMintable,
+	ERC721Burnable,
+	ERC721Metadata,
+	Collection,
+	TokenProperties
+{}
addedjs-packages/evm-abi/api/UniqueNativeFungible.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/UniqueNativeFungible.sol
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x1313556c
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	/// @dev EVM selector for this function is: 0xec069398,
+	///  or in textual repr: balanceOfCross((address,uint256))
+	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0x2ada85ff,
+	///  or in textual repr: transferCross((address,uint256),uint256)
+	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		CrossAddress memory from,
+		CrossAddress memory to,
+		uint256 amount
+	) external returns (bool);
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+	event Transfer(address indexed from, address indexed to, uint256 value);
+	event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+	/// @dev EVM selector for this function is: 0xdd62ed3e,
+	///  or in textual repr: allowance(address,address)
+	function allowance(address owner, address spender) external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0x095ea7b3,
+	///  or in textual repr: approve(address,uint256)
+	function approve(address spender, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0x70a08231,
+	///  or in textual repr: balanceOf(address)
+	function balanceOf(address owner) external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0x313ce567,
+	///  or in textual repr: decimals()
+	function decimals() external view returns (uint8);
+
+	/// @dev EVM selector for this function is: 0x06fdde03,
+	///  or in textual repr: name()
+	function name() external view returns (string memory);
+
+	/// @dev EVM selector for this function is: 0x95d89b41,
+	///  or in textual repr: symbol()
+	function symbol() external view returns (string memory);
+
+	/// @dev EVM selector for this function is: 0x18160ddd,
+	///  or in textual repr: totalSupply()
+	function totalSupply() external view returns (uint256);
+
+	/// @dev EVM selector for this function is: 0xa9059cbb,
+	///  or in textual repr: transfer(address,uint256)
+	function transfer(address to, uint256 amount) external returns (bool);
+
+	/// @dev EVM selector for this function is: 0x23b872dd,
+	///  or in textual repr: transferFrom(address,address,uint256)
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) external returns (bool);
+}
+
+interface UniqueNativeFungible is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
addedjs-packages/evm-abi/api/UniqueRefungible.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/UniqueRefungible.sol
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev inlined interface
+interface ERC721TokenEvent {
+	event TokenChanged(uint256 indexed tokenId);
+}
+
+/// @title A contract that allows to set and delete token properties and change token property permissions.
+/// @dev the ERC-165 identifier for this interface is 0xde0695c2
+interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
+	// /// @notice Set permissions for token property.
+	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	// /// @param key Property key.
+	// /// @param isMutable Permission to mutate property.
+	// /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
+	// /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
+	// /// @dev EVM selector for this function is: 0x222d97fa,
+	// ///  or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
+	// function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
+
+	/// @notice Set permissions for token property.
+	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
+	/// @param permissions Permissions for keys.
+	/// @dev EVM selector for this function is: 0xbd92983a,
+	///  or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
+	function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
+
+	/// @notice Get permissions for token properties.
+	/// @dev EVM selector for this function is: 0xf23d7790,
+	///  or in textual repr: tokenPropertyPermissions()
+	function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
+
+	// /// @notice Set token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @param value Property value.
+	// /// @dev EVM selector for this function is: 0x1752d67b,
+	// ///  or in textual repr: setProperty(uint256,string,bytes)
+	// function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
+
+	/// @notice Set token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param properties settable properties
+	/// @dev EVM selector for this function is: 0x14ed3a6e,
+	///  or in textual repr: setProperties(uint256,(string,bytes)[])
+	function setProperties(uint256 tokenId, Property[] memory properties) external;
+
+	// /// @notice Delete token property value.
+	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
+	// /// @param tokenId ID of the token.
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x066111d1,
+	// ///  or in textual repr: deleteProperty(uint256,string)
+	// function deleteProperty(uint256 tokenId, string memory key) external;
+
+	/// @notice Delete token properties value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param keys Properties key.
+	/// @dev EVM selector for this function is: 0xc472d371,
+	///  or in textual repr: deleteProperties(uint256,string[])
+	function deleteProperties(uint256 tokenId, string[] memory keys) external;
+
+	/// @notice Get token property value.
+	/// @dev Throws error if key not found
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @return Property value bytes
+	/// @dev EVM selector for this function is: 0x7228c327,
+	///  or in textual repr: property(uint256,string)
+	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
+}
+
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+struct Property {
+	string key;
+	bytes value;
+}
+
+/// Ethereum representation of Token Property Permissions.
+struct TokenPropertyPermission {
+	/// Token property key.
+	string key;
+	/// Token property permissions.
+	PropertyPermission[] permissions;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+struct PropertyPermission {
+	/// TokenPermission field.
+	TokenPermissionField code;
+	/// TokenPermission value.
+	bool value;
+}
+
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+enum TokenPermissionField {
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	Mutable,
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	TokenOwner,
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	CollectionAdmin
+}
+
+/// @title A contract that allows you to work with collections.
+/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
+interface Collection is Dummy, ERC165 {
+	// /// Set collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @param value Propery value.
+	// /// @dev EVM selector for this function is: 0x2f073f66,
+	// ///  or in textual repr: setCollectionProperty(string,bytes)
+	// function setCollectionProperty(string memory key, bytes memory value) external;
+
+	/// Set collection properties.
+	///
+	/// @param properties Vector of properties key/value pair.
+	/// @dev EVM selector for this function is: 0x50b26b2a,
+	///  or in textual repr: setCollectionProperties((string,bytes)[])
+	function setCollectionProperties(Property[] memory properties) external;
+
+	// /// Delete collection property.
+	// ///
+	// /// @param key Property key.
+	// /// @dev EVM selector for this function is: 0x7b7debce,
+	// ///  or in textual repr: deleteCollectionProperty(string)
+	// function deleteCollectionProperty(string memory key) external;
+
+	/// Delete collection properties.
+	///
+	/// @param keys Properties keys.
+	/// @dev EVM selector for this function is: 0xee206ee3,
+	///  or in textual repr: deleteCollectionProperties(string[])
+	function deleteCollectionProperties(string[] memory keys) external;
+
+	/// Get collection property.
+	///
+	/// @dev Throws error if key not found.
+	///
+	/// @param key Property key.
+	/// @return bytes The property corresponding to the key.
+	/// @dev EVM selector for this function is: 0xcf24fd6d,
+	///  or in textual repr: collectionProperty(string)
+	function collectionProperty(string memory key) external view returns (bytes memory);
+
+	/// Get collection properties.
+	///
+	/// @param keys Properties keys. Empty keys for all propertyes.
+	/// @return Vector of properties key/value pairs.
+	/// @dev EVM selector for this function is: 0x285fb8e6,
+	///  or in textual repr: collectionProperties(string[])
+	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
+
+	// /// Set the sponsor of the collection.
+	// ///
+	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	// ///
+	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
+	// /// @dev EVM selector for this function is: 0x7623402e,
+	// ///  or in textual repr: setCollectionSponsor(address)
+	// function setCollectionSponsor(address sponsor) external;
+
+	/// Set the sponsor of the collection.
+	///
+	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
+	///
+	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
+	/// @dev EVM selector for this function is: 0x84a1d5a8,
+	///  or in textual repr: setCollectionSponsorCross((address,uint256))
+	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
+
+	/// Whether there is a pending sponsor.
+	/// @dev EVM selector for this function is: 0x058ac185,
+	///  or in textual repr: hasCollectionPendingSponsor()
+	function hasCollectionPendingSponsor() external view returns (bool);
+
+	/// Collection sponsorship confirmation.
+	///
+	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
+	/// @dev EVM selector for this function is: 0x3c50e97a,
+	///  or in textual repr: confirmCollectionSponsorship()
+	function confirmCollectionSponsorship() external;
+
+	/// Remove collection sponsor.
+	/// @dev EVM selector for this function is: 0x6e0326a3,
+	///  or in textual repr: removeCollectionSponsor()
+	function removeCollectionSponsor() external;
+
+	/// Get current sponsor.
+	///
+	/// @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 (CrossAddress memory);
+
+	/// Get current collection limits.
+	///
+	/// @return Array of collection limits
+	/// @dev EVM selector for this function is: 0xf63bc572,
+	///  or in textual repr: collectionLimits()
+	function collectionLimits() external view returns (CollectionLimit[] memory);
+
+	/// Set limits for the collection.
+	/// @dev Throws error if limit not found.
+	/// @param limit Some limit.
+	/// @dev EVM selector for this function is: 0x2316ee74,
+	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
+	function setCollectionLimit(CollectionLimit memory limit) external;
+
+	/// Get contract address.
+	/// @dev EVM selector for this function is: 0xf6b4dfb4,
+	///  or in textual repr: contractAddress()
+	function contractAddress() external view returns (address);
+
+	/// Add collection admin.
+	/// @param newAdmin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x859aa7d6,
+	///  or in textual repr: addCollectionAdminCross((address,uint256))
+	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
+
+	/// Remove collection admin.
+	/// @param admin Cross account administrator address.
+	/// @dev EVM selector for this function is: 0x6c0cd173,
+	///  or in textual repr: removeCollectionAdminCross((address,uint256))
+	function removeCollectionAdminCross(CrossAddress memory admin) external;
+
+	// /// Add collection admin.
+	// /// @param newAdmin Address of the added administrator.
+	// /// @dev EVM selector for this function is: 0x92e462c7,
+	// ///  or in textual repr: addCollectionAdmin(address)
+	// function addCollectionAdmin(address newAdmin) external;
+
+	// /// Remove collection admin.
+	// ///
+	// /// @param admin Address of the removed administrator.
+	// /// @dev EVM selector for this function is: 0xfafd7b42,
+	// ///  or in textual repr: removeCollectionAdmin(address)
+	// function removeCollectionAdmin(address admin) external;
+
+	/// @dev EVM selector for this function is: 0x0b9f3890,
+	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
+	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
+	// /// @dev EVM selector for this function is: 0x112d4586,
+	// ///  or in textual repr: setCollectionNesting(bool)
+	// function setCollectionNesting(bool enable) external;
+
+	// /// Toggle accessibility of collection nesting.
+	// ///
+	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
+	// /// @param collections Addresses of collections that will be available for nesting.
+	// /// @dev EVM selector for this function is: 0x64872396,
+	// ///  or in textual repr: setCollectionNesting(bool,address[])
+	// function setCollectionNesting(bool enable, address[] memory collections) external;
+
+	/// @dev EVM selector for this function is: 0x92c660a8,
+	///  or in textual repr: collectionNesting()
+	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
+
+	// /// Returns nesting for a collection
+	// /// @dev EVM selector for this function is: 0x22d25bfe,
+	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
+	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
+
+	// /// Returns permissions for a collection
+	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
+	// ///  or in textual repr: collectionNestingPermissions()
+	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
+
+	/// Set the collection access method.
+	/// @param mode Access mode
+	/// @dev EVM selector for this function is: 0x41835d4c,
+	///  or in textual repr: setCollectionAccess(uint8)
+	function setCollectionAccess(AccessMode mode) external;
+
+	/// Checks that user allowed to operate with collection.
+	///
+	/// @param user User address to check.
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(CrossAddress memory user) external view returns (bool);
+
+	// /// Add the user to the allowed list.
+	// ///
+	// /// @param user Address of a trusted user.
+	// /// @dev EVM selector for this function is: 0x67844fe6,
+	// ///  or in textual repr: addToCollectionAllowList(address)
+	// function addToCollectionAllowList(address user) external;
+
+	/// Add user to allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0xa0184a3a,
+	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
+	function addToCollectionAllowListCross(CrossAddress memory user) external;
+
+	// /// Remove the user from the allowed list.
+	// ///
+	// /// @param user Address of a removed user.
+	// /// @dev EVM selector for this function is: 0x85c51acb,
+	// ///  or in textual repr: removeFromCollectionAllowList(address)
+	// function removeFromCollectionAllowList(address user) external;
+
+	/// Remove user from allowed list.
+	///
+	/// @param user User cross account address.
+	/// @dev EVM selector for this function is: 0x09ba452a,
+	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
+	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
+
+	/// Switch permission for minting.
+	///
+	/// @param mode Enable if "true".
+	/// @dev EVM selector for this function is: 0x00018e84,
+	///  or in textual repr: setCollectionMintMode(bool)
+	function setCollectionMintMode(bool mode) external;
+
+	// /// Check that account is the owner or admin of the collection
+	// ///
+	// /// @param user account to verify
+	// /// @return "true" if account is the owner or admin
+	// /// @dev EVM selector for this function is: 0x9811b0c7,
+	// ///  or in textual repr: isOwnerOrAdmin(address)
+	// function isOwnerOrAdmin(address user) external view returns (bool);
+
+	/// Check that account is the owner or admin of the collection
+	///
+	/// @param user User cross account to verify
+	/// @return "true" if account is the owner or admin
+	/// @dev EVM selector for this function is: 0x3e75a905,
+	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
+	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
+
+	/// Returns collection type
+	///
+	/// @return `Fungible` or `NFT` or `ReFungible`
+	/// @dev EVM selector for this function is: 0xd34b55b8,
+	///  or in textual repr: uniqueCollectionType()
+	function uniqueCollectionType() external view returns (string memory);
+
+	/// Get collection owner.
+	///
+	/// @return Tuble with sponsor address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0xdf727d3b,
+	///  or in textual repr: collectionOwner()
+	function collectionOwner() external view returns (CrossAddress memory);
+
+	// /// Changes collection owner to another account
+	// ///
+	// /// @dev Owner can be changed only by current owner
+	// /// @param newOwner new owner account
+	// /// @dev EVM selector for this function is: 0x4f53e226,
+	// ///  or in textual repr: changeCollectionOwner(address)
+	// function changeCollectionOwner(address newOwner) external;
+
+	/// Get collection administrators
+	///
+	/// @return Vector of tuples with admins address and his substrate mirror.
+	/// If address is canonical then substrate mirror is zero and vice versa.
+	/// @dev EVM selector for this function is: 0x5813216b,
+	///  or in textual repr: collectionAdmins()
+	function collectionAdmins() external view returns (CrossAddress[] memory);
+
+	/// Changes collection owner to another account
+	///
+	/// @dev Owner can be changed only by current owner
+	/// @param newOwner new owner cross account
+	/// @dev EVM selector for this function is: 0x6496c497,
+	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
+	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+struct CollectionNestingPermission {
+	CollectionPermissionField field;
+	bool value;
+}
+
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+enum CollectionPermissionField {
+	/// Owner of token can nest tokens under it.
+	TokenOwner,
+	/// Admin of token collection can nest tokens under token.
+	CollectionAdmin
+}
+
+/// Nested collections.
+struct CollectionNesting {
+	bool token_owner;
+	uint256[] ids;
+}
+
+/// Nested collections and permissions
+struct CollectionNestingAndPermission {
+	/// Owner of token can nest tokens under it.
+	bool token_owner;
+	/// Admin of token collection can nest tokens under token.
+	bool collection_admin;
+	/// If set - only tokens from specified collections can be nested.
+	address[] restricted;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+struct CollectionLimit {
+	CollectionLimitField field;
+	OptionUint256 value;
+}
+
+/// Optional value
+struct OptionUint256 {
+	/// Shows the status of accessibility of value
+	bool status;
+	/// Actual value if `status` is true
+	uint256 value;
+}
+
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+enum CollectionLimitField {
+	/// How many tokens can a user have on one account.
+	AccountTokenOwnership,
+	/// How many bytes of data are available for sponsorship.
+	SponsoredDataSize,
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	SponsoredDataRateLimit,
+	/// How many tokens can be mined into this collection.
+	TokenLimit,
+	/// Timeouts for transfer sponsoring.
+	SponsorTransferTimeout,
+	/// Timeout for sponsoring an approval in passed blocks.
+	SponsorApproveTimeout,
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
+	OwnerCanTransfer,
+	/// Can the collection owner burn other people's tokens.
+	OwnerCanDestroy,
+	/// Is it possible to send tokens from this collection between users.
+	TransferEnabled
+}
+
+/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
+/// @dev See https://eips.ethereum.org/EIPS/eip-721
+/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
+interface ERC721Metadata is Dummy, ERC165 {
+	// /// @notice A descriptive name for a collection of NFTs in this contract
+	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+	// /// @dev EVM selector for this function is: 0x06fdde03,
+	// ///  or in textual repr: name()
+	// function name() external view returns (string memory);
+
+	// /// @notice An abbreviated name for NFTs in this contract
+	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
+	// /// @dev EVM selector for this function is: 0x95d89b41,
+	// ///  or in textual repr: symbol()
+	// function symbol() external view returns (string memory);
+
+	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
+	///
+	/// @dev If the token has a `url` property and it is not empty, it is returned.
+	///  Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
+	///  If the collection property `baseURI` is empty or absent, return "" (empty string)
+	///  otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
+	///  otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
+	///
+	/// @return token's const_metadata
+	/// @dev EVM selector for this function is: 0xc87b56dd,
+	///  or in textual repr: tokenURI(uint256)
+	function tokenURI(uint256 tokenId) external view returns (string memory);
+}
+
+/// @title ERC721 Token that can be irreversibly burned (destroyed).
+/// @dev the ERC-165 identifier for this interface is 0x42966c68
+interface ERC721Burnable is Dummy, ERC165 {
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
+	///  operator of the current owner.
+	/// @param tokenId The RFT to approve
+	/// @dev EVM selector for this function is: 0x42966c68,
+	///  or in textual repr: burn(uint256)
+	function burn(uint256 tokenId) external;
+}
+
+/// @title ERC721 minting logic.
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
+	/// @notice Function to mint a token.
+	/// @param to The new owner
+	/// @return uint256 The id of the newly minted token
+	/// @dev EVM selector for this function is: 0x6a627842,
+	///  or in textual repr: mint(address)
+	function mint(address to) external returns (uint256);
+
+	// /// @notice Function to mint a token.
+	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
+	// ///  unlike standard, you can't specify it manually
+	// /// @param to The new owner
+	// /// @param tokenId ID of the minted RFT
+	// /// @dev EVM selector for this function is: 0x40c10f19,
+	// ///  or in textual repr: mint(address,uint256)
+	// function mint(address to, uint256 tokenId) external returns (bool);
+
+	/// @notice Function to mint token with the given tokenUri.
+	/// @param to The new owner
+	/// @param tokenUri Token URI that would be stored in the NFT properties
+	/// @return uint256 The id of the newly minted token
+	/// @dev EVM selector for this function is: 0x45c17782,
+	///  or in textual repr: mintWithTokenURI(address,string)
+	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
+	// /// @notice Function to mint token with the given tokenUri.
+	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
+	// ///  unlike standard, you can't specify it manually
+	// /// @param to The new owner
+	// /// @param tokenId ID of the minted RFT
+	// /// @param tokenUri Token URI that would be stored in the RFT properties
+	// /// @dev EVM selector for this function is: 0x50bb4e7f,
+	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
+	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
+
+}
+
+/// @title Unique extensions for ERC721.
+/// @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,
+	///  or in textual repr: name()
+	function name() external view returns (string memory);
+
+	/// @notice An abbreviated name for NFTs in this contract
+	/// @dev EVM selector for this function is: 0x95d89b41,
+	///  or in textual repr: symbol()
+	function symbol() external view returns (string memory);
+
+	/// @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);
+
+	// /// Returns the owner (in cross format) of the token.
+	// ///
+	// /// @param tokenId Id for the token.
+	// /// @dev EVM selector for this function is: 0x2b29dace,
+	// ///  or in textual repr: crossOwnerOf(uint256)
+	// function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
+
+	/// Returns the owner (in cross format) of the token.
+	///
+	/// @param tokenId Id for the token.
+	/// @dev EVM selector for this function is: 0xcaa3a4d0,
+	///  or in textual repr: ownerOfCross(uint256)
+	function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
+
+	/// @notice Count all RFTs assigned to an owner
+	/// @param owner An cross address for whom to query the balance
+	/// @return The number of RFTs owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0xec069398,
+	///  or in textual repr: balanceOfCross((address,uint256))
+	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+	/// Returns the token properties.
+	///
+	/// @param tokenId Id for the token.
+	/// @param keys Properties keys. Empty keys for all propertyes.
+	/// @return Vector of properties key/value pairs.
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+
+	/// @notice Transfer ownership of an RFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid RFT.
+	///  Throws if RFT pieces have multiple owners.
+	/// @param to The new owner
+	/// @param tokenId The RFT to transfer
+	/// @dev EVM selector for this function is: 0xa9059cbb,
+	///  or in textual repr: transfer(address,uint256)
+	function transfer(address to, uint256 tokenId) external;
+
+	/// @notice Transfer ownership of an RFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid RFT.
+	///  Throws if RFT pieces have multiple owners.
+	/// @param to The new owner
+	/// @param tokenId The RFT to transfer
+	/// @dev EVM selector for this function is: 0x2ada85ff,
+	///  or in textual repr: transferCross((address,uint256),uint256)
+	function transferCross(CrossAddress memory to, uint256 tokenId) external;
+
+	/// @notice Transfer ownership of an RFT
+	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
+	///  is the zero address. Throws if `tokenId` is not a valid RFT.
+	///  Throws if RFT pieces have multiple owners.
+	/// @param to The new owner
+	/// @param tokenId The RFT to transfer
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		CrossAddress memory from,
+		CrossAddress memory to,
+		uint256 tokenId
+	) external;
+
+	// /// @notice Burns a specific ERC721 token.
+	// /// @dev Throws unless `msg.sender` is the current owner or an authorized
+	// ///  operator for this RFT. Throws if `from` is not the current owner. Throws
+	// ///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+	// ///  Throws if RFT pieces have multiple owners.
+	// /// @param from The current owner of the RFT
+	// /// @param tokenId The RFT to transfer
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 tokenId) external;
+
+	/// @notice Burns a specific ERC721 token.
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this RFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+	///  Throws if RFT pieces have multiple owners.
+	/// @param from The current owner of the RFT
+	/// @param tokenId The RFT to transfer
+	/// @dev EVM selector for this function is: 0xbb2f5a58,
+	///  or in textual repr: burnFromCross((address,uint256),uint256)
+	function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
+
+	/// @notice Returns next free RFT ID.
+	/// @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
+	// /// @param to The new owner
+	// /// @param tokenIds IDs of the minted RFTs
+	// /// @dev EVM selector for this function is: 0x44a9945e,
+	// ///  or in textual repr: mintBulk(address,uint256[])
+	// function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
+
+	/// @notice Function to mint a token.
+	/// @param tokenProperties Properties of minted token
+	/// @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.
+	// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
+	// ///  numbers and first number should be obtained with `nextTokenId` method
+	// /// @param to The new owner
+	// /// @param tokens array of pairs of token ID and token URI for minted tokens
+	// /// @dev EVM selector for this function is: 0x36543006,
+	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
+	// function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
+
+	/// @notice Function to mint a 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(CrossAddress memory to, Property[] memory properties) external returns (uint256);
+
+	/// Returns EVM address for refungible token
+	///
+	/// @param token ID of the token
+	/// @dev EVM selector for this function is: 0xab76fac6,
+	///  or in textual repr: tokenContractAddress(uint256)
+	function tokenContractAddress(uint256 token) external view returns (address);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
+}
+
+/// Data for creation token with uri.
+struct TokenUri {
+	/// Id of new token.
+	uint256 id;
+	/// Uri of new token.
+	string uri;
+}
+
+/// Token minting parameters
+struct MintTokenData {
+	/// 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
+interface ERC721Enumerable is Dummy, ERC165 {
+	/// @notice Enumerate valid RFTs
+	/// @param index A counter less than `totalSupply()`
+	/// @return The token identifier for the `index`th NFT,
+	///  (sort order not specified)
+	/// @dev EVM selector for this function is: 0x4f6ccce7,
+	///  or in textual repr: tokenByIndex(uint256)
+	function tokenByIndex(uint256 index) external view returns (uint256);
+
+	/// Not implemented
+	/// @dev EVM selector for this function is: 0x2f745c59,
+	///  or in textual repr: tokenOfOwnerByIndex(address,uint256)
+	function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
+
+	/// @notice Count RFTs tracked by this contract
+	/// @return A count of valid RFTs tracked by this contract, where each one of
+	///  them has an assigned and queryable owner not equal to the zero address
+	/// @dev EVM selector for this function is: 0x18160ddd,
+	///  or in textual repr: totalSupply()
+	function totalSupply() external view returns (uint256);
+}
+
+/// @dev inlined interface
+interface ERC721Events {
+	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
+	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
+	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
+}
+
+/// @title ERC-721 Non-Fungible Token Standard
+/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
+/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+interface ERC721 is Dummy, ERC165, ERC721Events {
+	/// @notice Count all RFTs assigned to an owner
+	/// @dev RFTs assigned to the zero address are considered invalid, and this
+	///  function throws for queries about the zero address.
+	/// @param owner An address for whom to query the balance
+	/// @return The number of RFTs owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0x70a08231,
+	///  or in textual repr: balanceOf(address)
+	function balanceOf(address owner) external view returns (uint256);
+
+	/// @notice Find the owner of an RFT
+	/// @dev RFTs assigned to zero address are considered invalid, and queries
+	///  about them do throw.
+	///  Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
+	///  the tokens that are partially owned.
+	/// @param tokenId The identifier for an RFT
+	/// @return The address of the owner of the RFT
+	/// @dev EVM selector for this function is: 0x6352211e,
+	///  or in textual repr: ownerOf(uint256)
+	function ownerOf(uint256 tokenId) external view returns (address);
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0xb88d4fde,
+	///  or in textual repr: safeTransferFrom(address,address,uint256,bytes)
+	function safeTransferFrom(
+		address from,
+		address to,
+		uint256 tokenId,
+		bytes memory data
+	) external;
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0x42842e0e,
+	///  or in textual repr: safeTransferFrom(address,address,uint256)
+	function safeTransferFrom(
+		address from,
+		address to,
+		uint256 tokenId
+	) external;
+
+	/// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
+	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
+	///  THEY MAY BE PERMANENTLY LOST
+	/// @dev Throws unless `msg.sender` is the current owner or an authorized
+	///  operator for this RFT. Throws if `from` is not the current owner. Throws
+	///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
+	///  Throws if RFT pieces have multiple owners.
+	/// @param from The current owner of the NFT
+	/// @param to The new owner
+	/// @param tokenId The NFT to transfer
+	/// @dev EVM selector for this function is: 0x23b872dd,
+	///  or in textual repr: transferFrom(address,address,uint256)
+	function transferFrom(
+		address from,
+		address to,
+		uint256 tokenId
+	) external;
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0x095ea7b3,
+	///  or in textual repr: approve(address,uint256)
+	function approve(address approved, uint256 tokenId) external;
+
+	/// @notice Sets or unsets the approval of a given operator.
+	///  The `operator` is allowed to transfer all token pieces of the `caller` on their behalf.
+	/// @param operator Operator
+	/// @param approved Should operator status be granted or revoked?
+	/// @dev EVM selector for this function is: 0xa22cb465,
+	///  or in textual repr: setApprovalForAll(address,bool)
+	function setApprovalForAll(address operator, bool approved) external;
+
+	/// @dev Not implemented
+	/// @dev EVM selector for this function is: 0x081812fc,
+	///  or in textual repr: getApproved(uint256)
+	function getApproved(uint256 tokenId) external view returns (address);
+
+	/// @notice Tells whether the given `owner` approves the `operator`.
+	/// @dev EVM selector for this function is: 0xe985e9c5,
+	///  or in textual repr: isApprovedForAll(address,address)
+	function isApprovedForAll(address owner, address operator) external view returns (bool);
+}
+
+interface UniqueRefungible is
+	Dummy,
+	ERC165,
+	ERC721,
+	ERC721Enumerable,
+	ERC721UniqueExtensions,
+	ERC721UniqueMintable,
+	ERC721Burnable,
+	ERC721Metadata,
+	Collection,
+	TokenProperties
+{}
addedjs-packages/evm-abi/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/api/UniqueRefungibleToken.sol
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: OTHER
+// This code is automatically generated
+
+pragma solidity >=0.8.0 <0.9.0;
+
+/// @dev common stubs holder
+interface Dummy {
+
+}
+
+interface ERC165 is Dummy {
+	function supportsInterface(bytes4 interfaceID) external view returns (bool);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
+interface ERC1633 is Dummy, ERC165 {
+	/// @dev EVM selector for this function is: 0x80a54001,
+	///  or in textual repr: parentToken()
+	function parentToken() external view returns (address);
+
+	/// @dev EVM selector for this function is: 0xd7f083f3,
+	///  or in textual repr: parentTokenId()
+	function parentTokenId() external view returns (uint256);
+}
+
+/// @dev the ERC-165 identifier for this interface is 0xedd3a564
+interface ERC20UniqueExtensions is Dummy, ERC165 {
+	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
+	/// @param owner crossAddress The address which owns the funds.
+	/// @param spender crossAddress The address which will spend the funds.
+	/// @return A uint256 specifying the amount of tokens still available for the spender.
+	/// @dev EVM selector for this function is: 0xe0af4bd7,
+	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
+	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
+
+	// /// @dev Function that burns an amount of the token of a given account,
+	// /// deducting from the sender's allowance for said account.
+	// /// @param from The account whose tokens will be burnt.
+	// /// @param amount The amount that will be burnt.
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 amount) external returns (bool);
+
+	/// @dev Function that burns an amount of the token of a given account,
+	/// deducting from the sender's allowance for said account.
+	/// @param from The account whose tokens will be burnt.
+	/// @param amount The amount that will be burnt.
+	/// @dev EVM selector for this function is: 0xbb2f5a58,
+	///  or in textual repr: burnFromCross((address,uint256),uint256)
+	function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
+
+	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
+	/// Beware that changing an allowance with this method brings the risk that someone may use both the old
+	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
+	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
+	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+	/// @param spender The crossaccount which will spend the funds.
+	/// @param amount The amount of tokens to be spent.
+	/// @dev EVM selector for this function is: 0x0ecd0ab0,
+	///  or in textual repr: approveCross((address,uint256),uint256)
+	function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
+
+	/// @notice Balance of account
+	/// @param owner An cross address for whom to query the balance
+	/// @return The number of fingibles owned by `owner`, possibly zero
+	/// @dev EVM selector for this function is: 0xec069398,
+	///  or in textual repr: balanceOfCross((address,uint256))
+	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
+
+	/// @dev Function that changes total amount of the tokens.
+	///  Throws if `msg.sender` doesn't owns all of the tokens.
+	/// @param amount New total amount of the tokens.
+	/// @dev EVM selector for this function is: 0xd2418ca7,
+	///  or in textual repr: repartition(uint256)
+	function repartition(uint256 amount) external returns (bool);
+
+	/// @dev Transfer token for a specified address
+	/// @param to The crossaccount to transfer to.
+	/// @param amount The amount to be transferred.
+	/// @dev EVM selector for this function is: 0x2ada85ff,
+	///  or in textual repr: transferCross((address,uint256),uint256)
+	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
+
+	/// @dev Transfer tokens from one address to another
+	/// @param from The address which you want to send tokens from
+	/// @param to The address which you want to transfer to
+	/// @param amount the amount of tokens to be transferred
+	/// @dev EVM selector for this function is: 0xd5cf430b,
+	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
+	function transferFromCross(
+		CrossAddress memory from,
+		CrossAddress memory to,
+		uint256 amount
+	) external returns (bool);
+}
+
+/// Cross account struct
+struct CrossAddress {
+	address eth;
+	uint256 sub;
+}
+
+/// @dev inlined interface
+interface ERC20Events {
+	event Transfer(address indexed from, address indexed to, uint256 value);
+	event Approval(address indexed owner, address indexed spender, uint256 value);
+}
+
+/// @title Standard ERC20 token
+///
+/// @dev Implementation of the basic standard token.
+/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
+/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+interface ERC20 is Dummy, ERC165, ERC20Events {
+	/// @return the name of the token.
+	/// @dev EVM selector for this function is: 0x06fdde03,
+	///  or in textual repr: name()
+	function name() external view returns (string memory);
+
+	/// @return the symbol of the token.
+	/// @dev EVM selector for this function is: 0x95d89b41,
+	///  or in textual repr: symbol()
+	function symbol() external view returns (string memory);
+
+	/// @dev Total number of tokens in existence
+	/// @dev EVM selector for this function is: 0x18160ddd,
+	///  or in textual repr: totalSupply()
+	function totalSupply() external view returns (uint256);
+
+	/// @dev Not supported
+	/// @dev EVM selector for this function is: 0x313ce567,
+	///  or in textual repr: decimals()
+	function decimals() external view returns (uint8);
+
+	/// @dev Gets the balance of the specified address.
+	/// @param owner The address to query the balance of.
+	/// @return An uint256 representing the amount owned by the passed address.
+	/// @dev EVM selector for this function is: 0x70a08231,
+	///  or in textual repr: balanceOf(address)
+	function balanceOf(address owner) external view returns (uint256);
+
+	/// @dev Transfer token for a specified address
+	/// @param to The address to transfer to.
+	/// @param amount The amount to be transferred.
+	/// @dev EVM selector for this function is: 0xa9059cbb,
+	///  or in textual repr: transfer(address,uint256)
+	function transfer(address to, uint256 amount) external returns (bool);
+
+	/// @dev Transfer tokens from one address to another
+	/// @param from address The address which you want to send tokens from
+	/// @param to address The address which you want to transfer to
+	/// @param amount uint256 the amount of tokens to be transferred
+	/// @dev EVM selector for this function is: 0x23b872dd,
+	///  or in textual repr: transferFrom(address,address,uint256)
+	function transferFrom(
+		address from,
+		address to,
+		uint256 amount
+	) external returns (bool);
+
+	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
+	/// Beware that changing an allowance with this method brings the risk that someone may use both the old
+	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
+	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
+	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+	/// @param spender The address which will spend the funds.
+	/// @param amount The amount of tokens to be spent.
+	/// @dev EVM selector for this function is: 0x095ea7b3,
+	///  or in textual repr: approve(address,uint256)
+	function approve(address spender, uint256 amount) external returns (bool);
+
+	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
+	/// @param owner address The address which owns the funds.
+	/// @param spender address The address which will spend the funds.
+	/// @return A uint256 specifying the amount of tokens still available for the spender.
+	/// @dev EVM selector for this function is: 0xdd62ed3e,
+	///  or in textual repr: allowance(address,address)
+	function allowance(address owner, address spender) external view returns (uint256);
+}
+
+interface UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
addedjs-packages/evm-abi/package.jsondiffbeforeafterboth
--- /dev/null
+++ b/js-packages/evm-abi/package.json
@@ -0,0 +1,12 @@
+{
+  "author": "Unique Network",
+  "license": "Apache 2.0",
+  "description": "EVM interfaces for Unique Network chains",
+  "engines": {
+    "node": ">=18"
+  },
+  "name": "@unique-nft/evm-abi",
+  "type": "module",
+  "version": "1.0.0",
+  "main": "index.js"
+}
modifiedjs-packages/package.jsondiffbeforeafterboth
--- a/js-packages/package.json
+++ b/js-packages/package.json
@@ -26,6 +26,7 @@
     "@types/node": "^20.8.10",
     "@typescript-eslint/eslint-plugin": "^6.10.0",
     "@typescript-eslint/parser": "^6.10.0",
+    "@unique-nft/evm-abi": "workspace:*",
     "@unique-nft/opal-testnet-types": "workspace:*",
     "@unique-nft/playgrounds": "workspace:*",
     "@unique/test-utils": "workspace:*",
@@ -58,6 +59,7 @@
   "packageManager": "yarn@3.6.1",
   "workspaces": [
     "types",
+    "evm-abi",
     "playgrounds",
     "scripts",
     "test-utils",
modifiedjs-packages/scripts/benchmarks/mintFee/index.tsdiffbeforeafterboth
--- a/js-packages/scripts/benchmarks/mintFee/index.ts
+++ b/js-packages/scripts/benchmarks/mintFee/index.ts
@@ -1,5 +1,5 @@
-import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {readFile} from 'fs/promises';
 import type {ICrossAccountId} from '@unique-nft/playgrounds/types.js';
 import type {IKeyringPair} from '@polkadot/types/types';
@@ -8,29 +8,31 @@
 import {createObjectCsvWriter} from 'csv-writer';
 import {convertToTokens, createCollectionForBenchmarks, PERMISSIONS, PROPERTIES} from '../utils/common.js';
 import {makeNames} from '@unique/test-utils/util.js';
-import type {ContractImports} from '@unique/tests/eth/util/playgrounds/types.js';
+import type {ContractImports} from '@unique/test-utils/eth/types.js';
 
 const {dirname} = makeNames(import.meta.url);
 
+const EVM_ABI_DIR = `${dirname}/../../../evm-abi`;
+
 export const CONTRACT_IMPORT: ContractImports[] = [
   {
-    fsPath: `${dirname}/../../../tests/eth/api/CollectionHelpers.sol`,
+    fsPath: `${EVM_ABI_DIR}/api/CollectionHelpers.sol`,
     solPath: 'eth/api/CollectionHelpers.sol',
   },
   {
-    fsPath: `${dirname}/../../../tests/eth/api/ContractHelpers.sol`,
+    fsPath: `${EVM_ABI_DIR}/api/ContractHelpers.sol`,
     solPath: 'eth/api/ContractHelpers.sol',
   },
   {
-    fsPath: `${dirname}/../../../tests/eth/api/UniqueRefungibleToken.sol`,
+    fsPath: `${EVM_ABI_DIR}/api/UniqueRefungibleToken.sol`,
     solPath: 'eth/api/UniqueRefungibleToken.sol',
   },
   {
-    fsPath: `${dirname}/../../../tests/eth/api/UniqueRefungible.sol`,
+    fsPath: `${EVM_ABI_DIR}/api/UniqueRefungible.sol`,
     solPath: 'eth/api/UniqueRefungible.sol',
   },
   {
-    fsPath: `${dirname}/../../../tests/eth/api/UniqueNFT.sol`,
+    fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`,
     solPath: 'eth/api/UniqueNFT.sol',
   },
 ];
modifiedjs-packages/scripts/benchmarks/nesting/index.tsdiffbeforeafterboth
--- a/js-packages/scripts/benchmarks/nesting/index.ts
+++ b/js-packages/scripts/benchmarks/nesting/index.ts
@@ -1,58 +1,60 @@
-import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {readFile} from 'fs/promises';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
 import {convertToTokens} from '../utils/common.js';
 import {makeNames} from '@unique/test-utils/util.js';
-import type {ContractImports} from '@unique/tests/eth/util/playgrounds/types.js';
+import type {ContractImports} from '@unique/test-utils/eth/types.js';
 import type {RMRKNestableMintable} from './ABIGEN/index.js';
 
 const {dirname} = makeNames(import.meta.url);
 
+const NODE_MODULES = `${dirname}/../../../../node_modules`;
+
 export const CONTRACT_IMPORT: ContractImports[] = [
   {
-    fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,
+    fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol`,
     solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,
+    fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol`,
     solPath: '@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC6059.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,
+    fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol`,
     solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol`,
     solPath: '@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
     solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol`,
     solPath: '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Address.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/Address.sol`,
     solPath: '@openzeppelin/contracts/utils/Address.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/Context.sol`,
     solPath: '@openzeppelin/contracts/utils/Context.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
+    fsPath: `${NODE_MODULES}/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
     solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,
+    fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol`,
     solPath: '@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol',
   },
   {
-    fsPath: `${dirname}/../../../../node_modules/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,
+    fsPath: `${NODE_MODULES}/@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol`,
     solPath: '@rmrk-team/evm-contracts/contracts/RMRK/core/IRMRKCore.sol',
   },
   {
modifiedjs-packages/scripts/benchmarks/opsFee/index.tsdiffbeforeafterboth
--- a/js-packages/scripts/benchmarks/opsFee/index.ts
+++ b/js-packages/scripts/benchmarks/opsFee/index.ts
@@ -1,7 +1,7 @@
-import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {readFile} from 'fs/promises';
-import {CollectionLimitField,  CreateCollectionData,  TokenPermissionField} from '@unique/tests/eth/util/playgrounds/types.js';
+import {CollectionLimitField,  CreateCollectionData,  TokenPermissionField} from '@unique/test-utils/eth/types.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {UniqueFTCollection, UniqueNFTCollection} from '@unique-nft/playgrounds/unique.js';
 import {Contract} from 'web3-eth-contract';
@@ -76,7 +76,7 @@
     PERMISSIONS,
   )) as UniqueNFTCollection;
 
-  const helperContract = await helper.ethNativeContract.collectionHelpers(ethSigner);
+  const helperContract = helper.ethNativeContract.collectionHelpers(ethSigner);
   let zeppelelinContract: Contract | null = null;
   const ZEPPELIN_OBJECT = '0x' + (await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.bin`)).toString();
   const ZEPPELIN_ABI = JSON.parse((await readFile(`${dirname}/../utils/openZeppelin/ERC721/bin/ZeppelinContract.abi`)).toString());
modifiedjs-packages/scripts/benchmarks/utils/common.tsdiffbeforeafterboth
--- a/js-packages/scripts/benchmarks/utils/common.ts
+++ b/js-packages/scripts/benchmarks/utils/common.ts
@@ -1,4 +1,4 @@
-import {EthUniqueHelper} from '@unique/tests/eth/util/playgrounds/unique.dev.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {UniqueNFTCollection, UniqueRFTCollection} from '@unique-nft/playgrounds/unique.js';
 import type {ITokenPropertyPermission, TCollectionMode} from '@unique-nft/playgrounds/types.js';
 import type {IKeyringPair} from '@polkadot/types/types';
modifiedjs-packages/scripts/calibrate.tsdiffbeforeafterboth
--- a/js-packages/scripts/calibrate.ts
+++ b/js-packages/scripts/calibrate.ts
@@ -1,6 +1,6 @@
 import type {IKeyringPair} from '@polkadot/types/types';
-import {usingEthPlaygrounds} from '@unique/tests/eth/util/index.js';
-import {EthUniqueHelper} from '@unique/tests//eth/util/playgrounds/unique.dev.js';
+import {usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 
 class Fract {
   static ZERO = new Fract(0n);
addedjs-packages/scripts/correctStateAfterMaintenance.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/scripts/correctStateAfterMaintenance.ts
@@ -0,0 +1,69 @@
+import config from '../tests/config.js';
+import {usingPlaygrounds} from '@unique/test-utils/util.js';
+import type {u32} from '@polkadot/types-codec';
+
+const WS_ENDPOINT = config.substrateUrl;
+const DONOR_SEED = '//Alice';
+
+export const main = async(options: { wsEndpoint: string; donorSeed: string } = {
+  wsEndpoint: WS_ENDPOINT,
+  donorSeed: DONOR_SEED,
+}) => {
+  await usingPlaygrounds(async (helper, privateKey) => {
+    const api = helper.getApi();
+
+    if((await api.query.maintenance.enabled()).valueOf()) {
+      throw Error('The network is still in maintenance mode');
+    }
+
+    const pendingBlocks = (
+      await api.query.appPromotion.pendingUnstake.entries()
+    ).map(([k, _v]) =>
+      (k.args[0] as u32).toNumber());
+
+    const currentBlock = (await api.query.system.number() as u32).toNumber();
+
+    const filteredBlocks = pendingBlocks.filter(b => currentBlock > b);
+
+    if(filteredBlocks.length != 0) {
+      console.log(`During maintenance mode, ${filteredBlocks.length} block(s) were not processed. Number(s): ${filteredBlocks}`);
+    } else {
+      console.log('Nothing to change');
+      return;
+    }
+
+    const skippedBlocks = chunk(filteredBlocks, 10);
+
+    const signer = await privateKey(options.donorSeed);
+
+    const txs = skippedBlocks.map((b) =>
+      api.tx.sudo.sudo(api.tx.appPromotion.forceUnstake(b)));
+
+
+    const promises = txs.map((tx) => () => helper.signTransaction(signer, tx));
+
+    await Promise.allSettled(promises.map((p) => p()));
+
+    const failedBlocks: number[] = [];
+    let isSuccess = true;
+
+    for(const b of filteredBlocks) {
+      if(((await api.query.appPromotion.pendingUnstake(b)).toJSON() as any[]).length != 0) {
+        failedBlocks.push(b);
+        isSuccess = false;
+      }
+    }
+
+    if(isSuccess) {
+      console.log('Done. %d block(s) were processed.', filteredBlocks.length);
+    } else {
+      throw new Error(`Something went wrong. Block(s) have not been processed: ${failedBlocks}`);
+    }
+
+
+  }, options.wsEndpoint);
+};
+
+const chunk = <T>(arr: T[], size: number) =>
+  Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
+    arr.slice(i * size, i * size + size));
addedjs-packages/scripts/runCheckState.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/scripts/runCheckState.ts
@@ -0,0 +1,10 @@
+import {main} from './correctStateAfterMaintenance.js';
+
+main({
+  wsEndpoint: process.env.WS_RPC!,
+  donorSeed: process.env.SUPERUSER_SEED!,
+}).then(() => process.exit(0))
+  .catch((e) => {
+    console.error(e);
+    process.exit(1);
+  });
addedjs-packages/test-utils/eth/index.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/test-utils/eth/index.ts
@@ -0,0 +1,616 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+/* eslint-disable function-call-argument-newline */
+
+import {readFile} from 'fs/promises';
+
+import * as web3 from 'web3';
+import {WebsocketProvider} from 'web3-core';
+import {Contract} from 'web3-eth-contract';
+
+// @ts-ignore
+import solc from 'solc';
+
+import {evmToAddress} from '@polkadot/util-crypto';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import {ArrangeGroup, DevUniqueHelper} from '@unique/test-utils/index.js';
+
+import type {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types.js';
+import {CollectionMode, CreateCollectionData} from './types.js';
+
+// Native contracts ABI
+import collectionHelpersAbi from '@unique-nft/evm-abi/abi/collectionHelpers.json' assert {type: 'json'};
+import nativeFungibleAbi from '@unique-nft/evm-abi/abi/nativeFungible.json' assert {type: 'json'};
+import fungibleAbi from '@unique-nft/evm-abi/abi/fungible.json' assert {type: 'json'};
+import fungibleDeprecatedAbi from '@unique-nft/evm-abi/abi/fungibleDeprecated.json' assert {type: 'json'};
+import nonFungibleAbi from '@unique-nft/evm-abi/abi/nonFungible.json' assert {type: 'json'};
+import nonFungibleDeprecatedAbi from '@unique-nft/evm-abi/abi/nonFungibleDeprecated.json' assert {type: 'json'};
+import refungibleAbi from '@unique-nft/evm-abi/abi/reFungible.json' assert {type: 'json'};
+import refungibleDeprecatedAbi from '@unique-nft/evm-abi/abi/reFungibleDeprecated.json' assert {type: 'json'};
+import refungibleTokenAbi from '@unique-nft/evm-abi/abi/reFungibleToken.json' assert {type: 'json'};
+import refungibleTokenDeprecatedAbi from '@unique-nft/evm-abi/abi/reFungibleTokenDeprecated.json' assert {type: 'json'};
+import contractHelpersAbi from '@unique-nft/evm-abi/abi/contractHelpers.json' assert {type: 'json'};
+import type {ICrossAccountId, TEthereumAccount, TCollectionMode} from '@unique-nft/playgrounds/types.js';
+
+class EthGroupBase {
+  helper: EthUniqueHelper;
+  gasPrice?: string;
+
+  constructor(helper: EthUniqueHelper) {
+    this.helper = helper;
+  }
+  async getGasPrice() {
+    if(this.gasPrice)
+      return this.gasPrice;
+    this.gasPrice = await this.helper.getWeb3().eth.getGasPrice();
+    return this.gasPrice;
+  }
+}
+
+class ContractGroup extends EthGroupBase {
+  async findImports(imports?: ContractImports[]) {
+    if(!imports) return function(path: string) {
+      return {error: `File not found: ${path}`};
+    };
+
+    const knownImports = {} as { [key: string]: string };
+    for(const imp of imports) {
+      knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
+    }
+
+    return function(path: string) {
+      if(path in knownImports) return {contents: knownImports[path]};
+      return {error: `File not found: ${path}`};
+    };
+  }
+
+  async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
+    const compiled = JSON.parse(solc.compile(JSON.stringify({
+      language: 'Solidity',
+      sources: {
+        [`${name}.sol`]: {
+          content: src,
+        },
+      },
+      settings: {
+        outputSelection: {
+          '*': {
+            '*': ['*'],
+          },
+        },
+      },
+    }), {import: await this.findImports(imports)}));
+
+    const hasErrors = compiled['errors']
+      && compiled['errors'].length > 0
+      && compiled.errors.some(function(err: any) {
+        return err.severity == 'error';
+      });
+
+    if(hasErrors) {
+      throw compiled.errors;
+    }
+    const out = compiled.contracts[`${name}.sol`][name];
+
+    return {
+      abi: out.abi,
+      object: '0x' + out.evm.bytecode.object,
+    };
+  }
+
+  async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number, args?: any[]): Promise<Contract> {
+    const compiledContract = await this.compile(name, src, imports);
+    return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas, args);
+  }
+
+  async deployByAbi(signer: string, abi: any, object: string, gas?: number, args?: any[]): Promise<Contract> {
+    const web3 = this.helper.getWeb3();
+    const contract = new web3.eth.Contract(abi, undefined, {
+      data: object,
+      from: signer,
+      gas: gas ?? this.helper.eth.DEFAULT_GAS,
+    });
+    return await contract.deploy({data: object, arguments: args}).send({from: signer});
+  }
+
+}
+
+class NativeContractGroup extends EthGroupBase {
+
+  contractHelpers(caller: string) {
+    const web3 = this.helper.getWeb3();
+    return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {
+      from: caller,
+      gas: this.helper.eth.DEFAULT_GAS,
+    });
+  }
+
+  collectionHelpers(caller: string) {
+    const web3 = this.helper.getWeb3();
+    return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {
+      from: caller,
+      gas: this.helper.eth.DEFAULT_GAS,
+    });
+  }
+
+  collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {
+    let abi;
+    if(address === this.helper.ethAddress.fromCollectionId(0)) {
+      abi = nativeFungibleAbi;
+    } else {
+      abi ={
+        'nft': nonFungibleAbi,
+        'rft': refungibleAbi,
+        'ft': fungibleAbi,
+      }[mode];
+    }
+    if(mergeDeprecated) {
+      const deprecated = {
+        'nft': nonFungibleDeprecatedAbi,
+        'rft': refungibleDeprecatedAbi,
+        'ft': fungibleDeprecatedAbi,
+      }[mode];
+      abi = [...abi, ...deprecated];
+    }
+    const web3 = this.helper.getWeb3();
+    return new web3.eth.Contract(abi as any, address, {
+      gas: this.helper.eth.DEFAULT_GAS,
+      ...(caller ? {from: caller} : {}),
+    });
+  }
+
+  collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string, mergeDeprecated = false) {
+    return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);
+  }
+
+  rftToken(address: string, caller?: string, mergeDeprecated = false) {
+    const web3 = this.helper.getWeb3();
+    const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;
+    return new web3.eth.Contract(abi as any, address, {
+      gas: this.helper.eth.DEFAULT_GAS,
+      ...(caller ? {from: caller} : {}),
+    });
+  }
+
+  rftTokenById(collectionId: number, tokenId: number, caller?: string, mergeDeprecated = false) {
+    return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller, mergeDeprecated);
+  }
+}
+
+class CreateCollectionTransaction {
+  signer: string;
+  data: CreateCollectionData;
+  mergeDeprecated: boolean;
+  helper: EthUniqueHelper;
+
+  constructor(helper: EthUniqueHelper, signer: string, data: CreateCollectionData, mergeDeprecated = false) {
+    this.helper = helper;
+    this.signer = signer;
+
+    let flags = 0;
+    // convert CollectionFlags to number and join them in one number
+    if(!data.flags) {
+      flags = 0;
+    } else if(typeof data.flags == 'number') {
+      flags = data.flags;
+    } else {
+      for(let i = 0; i < data.flags.length; i++){
+        const flag = data.flags[i];
+        flags = flags | flag;
+      }
+    }
+    data.flags = flags;
+
+    this.data = data;
+    this.mergeDeprecated = mergeDeprecated;
+  }
+
+  // eslint-disable-next-line require-await
+  private async createTransaction() {
+    const collectionHelper = this.helper.ethNativeContract.collectionHelpers(this.signer);
+    let collectionMode;
+    switch (this.data.collectionMode) {
+      case 'nft': collectionMode = CollectionMode.Nonfungible; break;
+      case 'rft': collectionMode = CollectionMode.Refungible; break;
+      case 'ft': collectionMode = CollectionMode.Fungible; break;
+    }
+
+    const tx = collectionHelper.methods.createCollection([
+      this.data.name,
+      this.data.description,
+      this.data.tokenPrefix,
+      collectionMode,
+      this.data.decimals,
+      this.data.properties,
+      this.data.tokenPropertyPermissions,
+      this.data.adminList,
+      this.data.nestingSettings,
+      this.data.limits,
+      this.data.pendingSponsor,
+      this.data.flags,
+    ]);
+    return tx;
+  }
+
+  async send(options?: any): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[], collection: Contract }> {
+    const collectionCreationPrice = {
+      value: Number(this.helper.balance.getCollectionCreationPrice()),
+    };
+    const tx = await this.createTransaction();
+    const result = await tx.send({...options, ...collectionCreationPrice});
+
+    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
+    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
+    const events = this.helper.eth.normalizeEvents(result.events);
+    const collection = await this.helper.ethNativeContract.collectionById(collectionId, this.data.collectionMode, this.signer, this.mergeDeprecated);
+
+    return {collectionId, collectionAddress, events, collection};
+  }
+
+  async call(options?: any) {
+    const collectionCreationPrice = {
+      value: Number(this.helper.balance.getCollectionCreationPrice()),
+    };
+    const tx = await this.createTransaction();
+
+    return await tx.call({...options, ...collectionCreationPrice});
+  }
+}
+
+
+class EthGroup extends EthGroupBase {
+  DEFAULT_GAS = 2_500_000;
+
+  createAccount() {
+    const web3 = this.helper.getWeb3();
+    const account = web3.eth.accounts.create();
+    web3.eth.accounts.wallet.add(account.privateKey);
+    return account.address;
+  }
+
+  async createAccountWithBalance(donor: IKeyringPair, amount = 600n) {
+    const account = this.createAccount();
+    await this.transferBalanceFromSubstrate(donor, account, amount);
+
+    return account;
+  }
+
+  async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount = 100n, inTokens = true) {
+    return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
+  }
+
+  async getCollectionCreationFee(signer: string) {
+    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+    return await collectionHelper.methods.collectionCreationFee().call();
+  }
+
+  async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {
+    if(!gasLimit) gasLimit = this.DEFAULT_GAS;
+    const web3 = this.helper.getWeb3();
+    // FIXME: can't send legacy transaction using tx.evm.call
+    const gasPrice = await web3.eth.getGasPrice();
+    // TODO: check execution status
+    await this.helper.executeExtrinsic(
+      signer,
+      'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
+      true,
+    );
+  }
+
+  async callEVM(signer: TEthereumAccount, contractAddress: string, abi: string) {
+    return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
+  }
+
+  createCollectionMethodName(mode: TCollectionMode) {
+    switch (mode) {
+      case 'ft':
+        return 'createFTCollection';
+      case 'nft':
+        return 'createNFTCollection';
+      case 'rft':
+        return 'createRFTCollection';
+    }
+  }
+
+  createCollection(signer: string, data: CreateCollectionData, mergeDeprecated = false): CreateCollectionTransaction {
+    return new CreateCollectionTransaction(this.helper, signer, data, mergeDeprecated);
+  }
+
+  createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
+  }
+
+  async createERC721MetadataCompatibleCollection(signer: string, data: CreateCollectionData, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+    const {collectionId, collectionAddress, events} = await this.createCollection(signer, data).send();
+
+    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+    return {collectionId, collectionAddress, events};
+  }
+
+  async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+    const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
+
+    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+    return {collectionId, collectionAddress, events};
+  }
+
+  createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
+  }
+
+  createFungibleCollection(signer: string, name: string, _decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'ft')).send();
+  }
+
+  async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
+
+    const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
+
+    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
+
+    return {collectionId, collectionAddress, events};
+  }
+
+  async deployCollectorContract(signer: string): Promise<Contract> {
+    return await this.helper.ethContract.deployByCode(signer, 'Collector', `
+    // SPDX-License-Identifier: UNLICENSED
+    pragma solidity ^0.8.6;
+
+    contract Collector {
+      uint256 collected;
+      fallback() external payable {
+        giveMoney();
+      }
+      function giveMoney() public payable {
+        collected += msg.value;
+      }
+      function getCollected() public view returns (uint256) {
+        return collected;
+      }
+      function getUnaccounted() public view returns (uint256) {
+        return address(this).balance - collected;
+      }
+
+      function withdraw(address payable target) public {
+        target.transfer(collected);
+        collected = 0;
+      }
+    }
+  `);
+  }
+
+  async deployFlipper(signer: string): Promise<Contract> {
+    return await this.helper.ethContract.deployByCode(signer, 'Flipper', `
+    // SPDX-License-Identifier: UNLICENSED
+    pragma solidity ^0.8.6;
+
+    contract Flipper {
+      bool value = false;
+      function flip() public {
+        value = !value;
+      }
+      function getValue() public view returns (bool) {
+        return value;
+      }
+    }
+  `);
+  }
+
+  async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
+    const before = await this.helper.balance.getEthereum(user);
+    await call();
+    // In dev mode, the transaction might not finish processing in time
+    await this.helper.wait.newBlocks(1);
+    const after = await this.helper.balance.getEthereum(user);
+
+    return before - after;
+  }
+
+  normalizeEvents(events: any): NormalizedEvent[] {
+    const output = [];
+    for(const key of Object.keys(events)) {
+      if(key.match(/^[0-9]+$/)) {
+        output.push(events[key]);
+      } else if(Array.isArray(events[key])) {
+        output.push(...events[key]);
+      } else {
+        output.push(events[key]);
+      }
+    }
+    output.sort((a, b) => a.logIndex - b.logIndex);
+    return output.map(({address, event, returnValues}) => {
+      const args: { [key: string]: string } = {};
+      for(const key of Object.keys(returnValues)) {
+        if(!key.match(/^[0-9]+$/)) {
+          args[key] = returnValues[key];
+        }
+      }
+      return {
+        address,
+        event,
+        args,
+      };
+    });
+  }
+
+  async calculateFee(address: ICrossAccountId, code: () => Promise<any>): Promise<bigint> {
+    const wrappedCode = async () => {
+      await code();
+      // In dev mode, the transaction might not finish processing in time
+      await this.helper.wait.newBlocks(1);
+    };
+    return await this.helper.arrange.calculcateFee(address, wrappedCode);
+  }
+}
+
+class EthAddressGroup extends EthGroupBase {
+  extractCollectionId(address: string): number {
+    if(!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
+    return parseInt(address.slice(address.length - 8), 16);
+  }
+
+  fromCollectionId(collectionId: number): string {
+    if(collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
+    return web3.default.utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
+  }
+
+  extractTokenId(address: string): { collectionId: number, tokenId: number } {
+    if(!address.startsWith('0x'))
+      throw 'address not starts with "0x"';
+    if(address.length > 42)
+      throw 'address length is more than 20 bytes';
+    return {
+      collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
+      tokenId: Number('0x' + address.substring(address.length - 8)),
+    };
+  }
+
+  fromTokenId(collectionId: number, tokenId: number): string {
+    return this.helper.util.getTokenAddress({collectionId, tokenId});
+  }
+
+  normalizeAddress(address: string): string {
+    return '0x' + address.substring(address.length - 40);
+  }
+}
+export class EthPropertyGroup extends EthGroupBase {
+  property(key: string, value: string): EthProperty {
+    return [
+      key,
+      '0x' + Buffer.from(value).toString('hex'),
+    ];
+  }
+}
+export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
+
+export class EthCrossAccountGroup extends EthGroupBase {
+  createAccount(): CrossAddress {
+    return this.fromAddress(this.helper.eth.createAccount());
+  }
+
+  async createAccountWithBalance(donor: IKeyringPair, amount = 100n) {
+    return this.fromAddress(await this.helper.eth.createAccountWithBalance(donor, amount));
+  }
+
+  fromAddress(address: TEthereumAccount): CrossAddress {
+    return {
+      eth: address,
+      sub: '0',
+    };
+  }
+
+  fromAddr(address: TEthereumAccount): [string, string] {
+    return [
+      address,
+      '0',
+    ];
+  }
+
+  fromKeyringPair(keyring: IKeyringPair): CrossAddress {
+    return {
+      eth: '0x0000000000000000000000000000000000000000',
+      sub: keyring.addressRaw,
+    };
+  }
+}
+
+export class FeeGas {
+  fee: number | bigint = 0n;
+
+  gas: number | bigint = 0n;
+
+  public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
+    const instance = new FeeGas();
+    instance.fee = instance.convertToTokens(fee);
+    instance.gas = await instance.convertToGas(fee, helper);
+    return instance;
+  }
+
+  private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
+    const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
+    return fee / gasPrice;
+  }
+
+  private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
+    return Number((value * 1000n) / nominal) / 1000;
+  }
+}
+
+class EthArrangeGroup extends ArrangeGroup {
+  declare helper: EthUniqueHelper;
+
+  constructor(helper: EthUniqueHelper) {
+    super(helper);
+    this.helper = helper;
+  }
+
+  async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
+    const fee = await this.calculcateFee(payer, promise);
+    return await FeeGas.build(this.helper, fee);
+  }
+}
+export class EthUniqueHelper extends DevUniqueHelper {
+  web3: web3.default | null = null;
+  web3Provider: WebsocketProvider | null = null;
+
+  eth: EthGroup;
+  ethAddress: EthAddressGroup;
+  ethCrossAccount: EthCrossAccountGroup;
+  ethNativeContract: NativeContractGroup;
+  ethContract: ContractGroup;
+  ethProperty: EthPropertyGroup;
+  declare arrange: EthArrangeGroup;
+  constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: { [key: string]: any } = {}) {
+    options.helperBase = options.helperBase ?? EthUniqueHelper;
+
+    super(logger, options);
+    this.eth = new EthGroup(this);
+    this.ethAddress = new EthAddressGroup(this);
+    this.ethCrossAccount = new EthCrossAccountGroup(this);
+    this.ethNativeContract = new NativeContractGroup(this);
+    this.ethContract = new ContractGroup(this);
+    this.ethProperty = new EthPropertyGroup(this);
+    this.arrange = new EthArrangeGroup(this);
+    super.arrange = this.arrange;
+  }
+
+  getWeb3(): web3.default {
+    if(this.web3 === null) throw Error('Web3 not connected');
+    return this.web3;
+  }
+
+  connectWeb3(wsEndpoint: string) {
+    if(this.web3 !== null) return;
+    this.web3Provider = new web3.default.providers.WebsocketProvider(wsEndpoint);
+    this.web3 = new web3.default(this.web3Provider);
+  }
+
+  override async disconnect() {
+    if(this.web3 === null) return;
+    this.web3Provider?.connection.close();
+
+    await super.disconnect();
+  }
+
+  override clearApi() {
+    super.clearApi();
+    this.web3 = null;
+  }
+
+  override clone(helperCls: EthUniqueHelperConstructor, options?: { [key: string]: any; }): EthUniqueHelper {
+    const newHelper = super.clone(helperCls, options) as EthUniqueHelper;
+    newHelper.web3 = this.web3;
+    newHelper.web3Provider = this.web3Provider;
+
+    return newHelper;
+  }
+}
addedjs-packages/test-utils/eth/types.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/test-utils/eth/types.ts
@@ -0,0 +1,133 @@
+import {CollectionFlag} from '@unique-nft/playgrounds/types.js';
+import type {TCollectionMode} from '@unique-nft/playgrounds/types.js';
+
+export interface ContractImports {
+  solPath: string;
+  fsPath: string;
+}
+
+export interface CompiledContract {
+  abi: any;
+  object: string;
+}
+
+export type NormalizedEvent = {
+  address: string,
+  event: string,
+  args: { [key: string]: string }
+};
+
+export interface OptionUint {
+  status: boolean,
+  value: bigint,
+}
+
+export type EthAddress = string;
+
+export interface CrossAddress {
+  readonly eth: EthAddress,
+  readonly sub: string | Uint8Array,
+}
+
+export type EthProperty = string[];
+
+export enum TokenPermissionField {
+  Mutable,
+  TokenOwner,
+  CollectionAdmin
+}
+
+export enum CollectionLimitField {
+  AccountTokenOwnership,
+	SponsoredDataSize,
+	SponsoredDataRateLimit,
+	TokenLimit,
+	SponsorTransferTimeout,
+	SponsorApproveTimeout,
+	OwnerCanTransfer,
+	OwnerCanDestroy,
+	TransferEnabled
+}
+
+export interface CollectionLimit {
+  field: CollectionLimitField,
+  value: OptionUint,
+}
+
+export interface CollectionLimitValue {
+  field: CollectionLimitField,
+  value: bigint,
+}
+
+export enum CollectionMode {
+	Nonfungible,
+	Fungible,
+	Refungible,
+}
+
+export interface PropertyPermission {
+  code: TokenPermissionField,
+  value: boolean,
+}
+export interface TokenPropertyPermission {
+  key: string,
+  permissions: PropertyPermission[],
+}
+export interface CollectionNestingAndPermission {
+  token_owner: boolean,
+  collection_admin: boolean,
+  restricted: string[],
+}
+
+export const emptyAddress: [string, string] = [
+  '0x0000000000000000000000000000000000000000',
+  '0',
+];
+
+export const CREATE_COLLECTION_DATA_DEFAULTS = {
+  decimals: 0,
+  properties: [],
+  tokenPropertyPermissions: [],
+  adminList: [],
+  nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
+  limits: [],
+  pendingSponsor: emptyAddress,
+  flags: 0,
+};
+
+export interface Property {
+  key: string;
+  value: Buffer;
+}
+
+export class CreateCollectionData {
+  name: string;
+  description: string;
+  tokenPrefix: string;
+  collectionMode: TCollectionMode;
+  decimals? = 0;
+  properties?: Property[] = [];
+  tokenPropertyPermissions?: TokenPropertyPermission[] = [];
+  adminList?: CrossAddress[] = [];
+  nestingSettings?: CollectionNestingAndPermission = {token_owner: false, collection_admin: false, restricted: []};
+  limits?: CollectionLimitValue[] = [];
+  pendingSponsor?: [string, string] = emptyAddress;
+  flags?: number | CollectionFlag[] = [0];
+
+  constructor(
+    name: string,
+    description: string,
+    tokenPrefix: string,
+    collectionMode: TCollectionMode,
+    decimals = 18,
+  ) {
+    this.name = name;
+    this.description = description;
+    this.tokenPrefix = tokenPrefix;
+    this.collectionMode = collectionMode;
+    if(collectionMode == 'ft')
+      this.decimals = decimals;
+    else
+      this.decimals = 0;
+  }
+}
addedjs-packages/test-utils/eth/util.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/test-utils/eth/util.ts
@@ -0,0 +1,106 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+import * as path from 'path';
+import type {IKeyringPair} from '@polkadot/types/types';
+
+import config from '../../tests/config.js';
+
+import {EthUniqueHelper} from './index.js';
+import {SilentLogger, SilentConsole} from '@unique/test-utils';
+import type {SchedKind} from '@unique/test-utils/util.js';
+
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import chaiLike from 'chai-like';
+import {getTestSeed, MINIMUM_DONOR_FUND, requirePalletsOrSkip, makeNames} from '@unique/test-utils/util.js';
+
+chai.use(chaiAsPromised);
+chai.use(chaiLike);
+export const expect = chai.expect;
+
+export enum SponsoringMode {
+  Disabled = 0,
+  Allowlisted = 1,
+  Generous = 2,
+}
+
+type PrivateKeyFn = (seed: string | {filename?: string, url?: string}) => Promise<IKeyringPair>;
+
+export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: PrivateKeyFn) => Promise<void>) => {
+  const silentConsole = new SilentConsole();
+  silentConsole.enable();
+
+  const helper = new EthUniqueHelper(new SilentLogger());
+
+  try {
+    await helper.connect(config.substrateUrl);
+    await helper.connectWeb3(config.substrateUrl);
+    const ss58Format = helper.chain.getChainProperties().ss58Format;
+    const privateKey: PrivateKeyFn = async (seed) => {
+      if(typeof seed === 'string') {
+        return helper.util.fromSeed(seed, ss58Format);
+      }
+      if(seed.url) {
+        const {filename} = makeNames(seed.url);
+        seed.filename = filename;
+      } else if(seed.filename) {
+        // Pass
+      } else {
+        throw new Error('no url nor filename set');
+      }
+      const actualSeed = getTestSeed(seed.filename);
+      let account = helper.util.fromSeed(actualSeed, ss58Format);
+      if(await helper.balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND) {
+        console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
+        account = helper.util.fromSeed('//Alice', ss58Format);
+      }
+      return account;
+    };
+    await code(helper, privateKey);
+  }
+  finally {
+    await helper.disconnect();
+    silentConsole.disable();
+  }
+};
+
+export function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+  (opts.only ? it.only :
+    opts.skip ? it.skip : it)(name, async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      if(opts.requiredPallets) {
+        requirePalletsOrSkip(this, helper, opts.requiredPallets);
+      }
+
+      await cb({helper, privateKey});
+    });
+  });
+}
+
+export function itEthIfWithPallet(name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+  return itEth(name, cb, {requiredPallets: required, ...opts});
+}
+
+itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEth(name, cb, {only: true});
+itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEth(name, cb, {skip: true});
+
+itEthIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {only: true});
+itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});
+itEth.ifWithPallets = itEthIfWithPallet;
+
+export function itSchedEth(
+  name: string,
+  cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any,
+  opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
+) {
+  itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
+  itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
+}
+itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {only: true});
+itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {skip: true});
+itSchedEth.ifWithPallets = itSchedIfWithPallets;
+
+function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
+  return itSchedEth(name, cb, {requiredPallets: required, ...opts});
+}
deletedjs-packages/tests/eth/abi/collectionHelpers.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/collectionHelpers.json
+++ /dev/null
@@ -1,267 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "collectionId",
-        "type": "address"
-      }
-    ],
-    "name": "CollectionChanged",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "collectionId",
-        "type": "address"
-      }
-    ],
-    "name": "CollectionCreated",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "collectionId",
-        "type": "address"
-      }
-    ],
-    "name": "CollectionDestroyed",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
-    ],
-    "name": "collectionAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionCreationFee",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "collectionAddress",
-        "type": "address"
-      }
-    ],
-    "name": "collectionId",
-    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "name", "type": "string" },
-          { "internalType": "string", "name": "description", "type": "string" },
-          {
-            "internalType": "string",
-            "name": "token_prefix",
-            "type": "string"
-          },
-          {
-            "internalType": "enum CollectionMode",
-            "name": "mode",
-            "type": "uint8"
-          },
-          { "internalType": "uint8", "name": "decimals", "type": "uint8" },
-          {
-            "components": [
-              { "internalType": "string", "name": "key", "type": "string" },
-              { "internalType": "bytes", "name": "value", "type": "bytes" }
-            ],
-            "internalType": "struct Property[]",
-            "name": "properties",
-            "type": "tuple[]"
-          },
-          {
-            "components": [
-              { "internalType": "string", "name": "key", "type": "string" },
-              {
-                "components": [
-                  {
-                    "internalType": "enum TokenPermissionField",
-                    "name": "code",
-                    "type": "uint8"
-                  },
-                  { "internalType": "bool", "name": "value", "type": "bool" }
-                ],
-                "internalType": "struct PropertyPermission[]",
-                "name": "permissions",
-                "type": "tuple[]"
-              }
-            ],
-            "internalType": "struct TokenPropertyPermission[]",
-            "name": "token_property_permissions",
-            "type": "tuple[]"
-          },
-          {
-            "components": [
-              { "internalType": "address", "name": "eth", "type": "address" },
-              { "internalType": "uint256", "name": "sub", "type": "uint256" }
-            ],
-            "internalType": "struct CrossAddress[]",
-            "name": "admin_list",
-            "type": "tuple[]"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "token_owner", "type": "bool" },
-              {
-                "internalType": "bool",
-                "name": "collection_admin",
-                "type": "bool"
-              },
-              {
-                "internalType": "address[]",
-                "name": "restricted",
-                "type": "address[]"
-              }
-            ],
-            "internalType": "struct CollectionNestingAndPermission",
-            "name": "nesting_settings",
-            "type": "tuple"
-          },
-          {
-            "components": [
-              {
-                "internalType": "enum CollectionLimitField",
-                "name": "field",
-                "type": "uint8"
-              },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct CollectionLimitValue[]",
-            "name": "limits",
-            "type": "tuple[]"
-          },
-          {
-            "components": [
-              { "internalType": "address", "name": "eth", "type": "address" },
-              { "internalType": "uint256", "name": "sub", "type": "uint256" }
-            ],
-            "internalType": "struct CrossAddress",
-            "name": "pending_sponsor",
-            "type": "tuple"
-          },
-          {
-            "internalType": "CollectionFlags",
-            "name": "flags",
-            "type": "uint8"
-          }
-        ],
-        "internalType": "struct CreateCollectionData",
-        "name": "data",
-        "type": "tuple"
-      }
-    ],
-    "name": "createCollection",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "payable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "name", "type": "string" },
-      { "internalType": "uint8", "name": "decimals", "type": "uint8" },
-      { "internalType": "string", "name": "description", "type": "string" },
-      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
-    ],
-    "name": "createFTCollection",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "payable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "name", "type": "string" },
-      { "internalType": "string", "name": "description", "type": "string" },
-      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
-    ],
-    "name": "createNFTCollection",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "payable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "name", "type": "string" },
-      { "internalType": "string", "name": "description", "type": "string" },
-      { "internalType": "string", "name": "tokenPrefix", "type": "string" }
-    ],
-    "name": "createRFTCollection",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "payable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "collectionAddress",
-        "type": "address"
-      }
-    ],
-    "name": "destroyCollection",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "collectionAddress",
-        "type": "address"
-      }
-    ],
-    "name": "isCollectionExist",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "collection", "type": "address" },
-      { "internalType": "string", "name": "baseUri", "type": "string" }
-    ],
-    "name": "makeCollectionERC721MetadataCompatible",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/contractHelpers.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/contractHelpers.json
+++ /dev/null
@@ -1,326 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "ContractSponsorRemoved",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "address",
-        "name": "sponsor",
-        "type": "address"
-      }
-    ],
-    "name": "ContractSponsorSet",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "address",
-        "name": "sponsor",
-        "type": "address"
-      }
-    ],
-    "name": "ContractSponsorshipConfirmed",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "allowed",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "allowlistEnabled",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "confirmSponsorship",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "contractOwner",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "hasPendingSponsor",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "hasSponsor",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "removeSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "selfSponsoredEnable",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "address", "name": "sponsor", "type": "address" }
-    ],
-    "name": "setSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "uint256", "name": "feeLimit", "type": "uint256" }
-    ],
-    "name": "setSponsoringFeeLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      {
-        "internalType": "enum SponsoringModeT",
-        "name": "mode",
-        "type": "uint8"
-      }
-    ],
-    "name": "setSponsoringMode",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "uint32", "name": "rateLimit", "type": "uint32" }
-    ],
-    "name": "setSponsoringRateLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "sponsor",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "status", "type": "bool" },
-          {
-            "components": [
-              { "internalType": "address", "name": "eth", "type": "address" },
-              { "internalType": "uint256", "name": "sub", "type": "uint256" }
-            ],
-            "internalType": "struct CrossAddress",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct OptionCrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "sponsoringEnabled",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "sponsoringFeeLimit",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      }
-    ],
-    "name": "sponsoringRateLimit",
-    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "address", "name": "user", "type": "address" },
-      { "internalType": "bool", "name": "isAllowed", "type": "bool" }
-    ],
-    "name": "toggleAllowed",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "internalType": "address",
-        "name": "contractAddress",
-        "type": "address"
-      },
-      { "internalType": "bool", "name": "enabled", "type": "bool" }
-    ],
-    "name": "toggleAllowlist",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/fungible.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/fungible.json
+++ /dev/null
@@ -1,722 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "spender",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Approval",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "from",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "to",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Transfer",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newAdmin",
-        "type": "tuple"
-      }
-    ],
-    "name": "addCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "addToCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "address", "name": "spender", "type": "address" }
-    ],
-    "name": "allowance",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "spender",
-        "type": "tuple"
-      }
-    ],
-    "name": "allowanceCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "allowlistedCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "spender", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "approve",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "spender",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "approveCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" }
-    ],
-    "name": "balanceOf",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      }
-    ],
-    "name": "balanceOfCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "burnFromCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newOwner",
-        "type": "tuple"
-      }
-    ],
-    "name": "changeCollectionOwnerCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionAdmins",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionHelperAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionLimits",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNesting",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionOwner",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "collectionProperties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "collectionProperty",
-    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionSponsor",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "confirmCollectionSponsorship",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "contractAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "decimals",
-    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "deleteCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "description",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "hasCollectionPendingSponsor",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "isOwnerOrAdminCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "mint",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "to", "type": "address" },
-          { "internalType": "uint256", "name": "amount", "type": "uint256" }
-        ],
-        "internalType": "struct AmountForAddress[]",
-        "name": "amounts",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "mintBulk",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "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" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "admin",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "removeCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeFromCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
-    ],
-    "name": "setCollectionAccess",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit",
-        "name": "limit",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
-    "name": "setCollectionMintMode",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "collectionNestingAndPermissions",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "properties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "sponsor",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionSponsorCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "symbol",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "totalSupply",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transfer",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFromCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "uniqueCollectionType",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/fungibleDeprecated.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/fungibleDeprecated.json
+++ /dev/null
@@ -1,151 +0,0 @@
-[
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newAdmin", "type": "address" }
-    ],
-    "name": "addCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "addToCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "burnFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newOwner", "type": "address" }
-    ],
-    "name": "changeCollectionOwner",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "deleteCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "isOwnerOrAdmin",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "admin", "type": "address" }
-    ],
-    "name": "removeCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "removeFromCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "sponsor", "type": "address" }
-    ],
-    "name": "setCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingPermissions",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionPermissionField",
-            "name": "field",
-            "type": "uint8"
-          },
-          { "internalType": "bool", "name": "value", "type": "bool" }
-        ],
-        "internalType": "struct CollectionNestingPermission[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingRestrictedCollectionIds",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
-        ],
-        "internalType": "struct CollectionNesting",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bool", "name": "enable", "type": "bool" },
-      {
-        "internalType": "address[]",
-        "name": "collections",
-        "type": "address[]"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/nativeFungible.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/nativeFungible.json
+++ /dev/null
@@ -1,201 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "spender",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Approval",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "from",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "to",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Transfer",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "address", "name": "spender", "type": "address" }
-    ],
-    "name": "allowance",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "spender", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "approve",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" }
-    ],
-    "name": "balanceOf",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      }
-    ],
-    "name": "balanceOfCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "decimals",
-    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "name",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "symbol",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "totalSupply",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transfer",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFromCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/nonFungible.json
+++ /dev/null
@@ -1,988 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "approved",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "Approval",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "operator",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "bool",
-        "name": "approved",
-        "type": "bool"
-      }
-    ],
-    "name": "ApprovalForAll",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "TokenChanged",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "from",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "to",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "Transfer",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newAdmin",
-        "type": "tuple"
-      }
-    ],
-    "name": "addCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "addToCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "allowlistedCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "approved", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "approve",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "approved",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "approveCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" }
-    ],
-    "name": "balanceOf",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      }
-    ],
-    "name": "balanceOfCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burn",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burnFromCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newOwner",
-        "type": "tuple"
-      }
-    ],
-    "name": "changeCollectionOwnerCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionAdmins",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionHelperAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionLimits",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNesting",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionOwner",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "collectionProperties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "collectionProperty",
-    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionSponsor",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "confirmCollectionSponsorship",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "contractAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "deleteCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "deleteProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "description",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "getApproved",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "hasCollectionPendingSponsor",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "address", "name": "operator", "type": "address" }
-    ],
-    "name": "isApprovedForAll",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "isOwnerOrAdminCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
-    "name": "mint",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          {
-            "components": [
-              { "internalType": "address", "name": "eth", "type": "address" },
-              { "internalType": "uint256", "name": "sub", "type": "uint256" }
-            ],
-            "internalType": "struct CrossAddress",
-            "name": "owner",
-            "type": "tuple"
-          },
-          {
-            "components": [
-              { "internalType": "string", "name": "key", "type": "string" },
-              { "internalType": "bytes", "name": "value", "type": "bytes" }
-            ],
-            "internalType": "struct Property[]",
-            "name": "properties",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct MintTokenData[]",
-        "name": "data",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "mintBulkCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "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" }
-    ],
-    "name": "mintWithTokenURI",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "name",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "nextTokenId",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "ownerOf",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "ownerOfCross",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "properties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" }
-    ],
-    "name": "property",
-    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "admin",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "removeCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeFromCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "safeTransferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "bytes", "name": "data", "type": "bytes" }
-    ],
-    "name": "safeTransferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "operator", "type": "address" },
-      { "internalType": "bool", "name": "approved", "type": "bool" }
-    ],
-    "name": "setApprovalForAll",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
-    ],
-    "name": "setCollectionAccess",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit",
-        "name": "limit",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
-    "name": "setCollectionMintMode",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "collectionNestingAndPermissions",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "properties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "sponsor",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionSponsorCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "properties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          {
-            "components": [
-              {
-                "internalType": "enum TokenPermissionField",
-                "name": "code",
-                "type": "uint8"
-              },
-              { "internalType": "bool", "name": "value", "type": "bool" }
-            ],
-            "internalType": "struct PropertyPermission[]",
-            "name": "permissions",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct TokenPropertyPermission[]",
-        "name": "permissions",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setTokenPropertyPermissions",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "symbol",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "index", "type": "uint256" }
-    ],
-    "name": "tokenByIndex",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "uint256", "name": "index", "type": "uint256" }
-    ],
-    "name": "tokenOfOwnerByIndex",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "tokenPropertyPermissions",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          {
-            "components": [
-              {
-                "internalType": "enum TokenPermissionField",
-                "name": "code",
-                "type": "uint8"
-              },
-              { "internalType": "bool", "name": "value", "type": "bool" }
-            ],
-            "internalType": "struct PropertyPermission[]",
-            "name": "permissions",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct TokenPropertyPermission[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "tokenURI",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "totalSupply",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transfer",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferFromCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "uniqueCollectionType",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/nonFungibleDeprecated.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/nonFungibleDeprecated.json
+++ /dev/null
@@ -1,172 +0,0 @@
-[
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newAdmin", "type": "address" }
-    ],
-    "name": "addCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "addToCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burnFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "deleteCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "isOwnerOrAdmin",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "admin", "type": "address" }
-    ],
-    "name": "removeCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "removeFromCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "sponsor", "type": "address" }
-    ],
-    "name": "setCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newOwner", "type": "address" }
-    ],
-    "name": "changeCollectionOwner",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" }
-    ],
-    "name": "deleteProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingPermissions",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionPermissionField",
-            "name": "field",
-            "type": "uint8"
-          },
-          { "internalType": "bool", "name": "value", "type": "bool" }
-        ],
-        "internalType": "struct CollectionNestingPermission[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingRestrictedCollectionIds",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
-        ],
-        "internalType": "struct CollectionNesting",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bool", "name": "enable", "type": "bool" },
-      {
-        "internalType": "address[]",
-        "name": "collections",
-        "type": "address[]"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/reFungible.json
+++ /dev/null
@@ -1,995 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "approved",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "Approval",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "operator",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "bool",
-        "name": "approved",
-        "type": "bool"
-      }
-    ],
-    "name": "ApprovalForAll",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "TokenChanged",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "from",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "to",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "uint256",
-        "name": "tokenId",
-        "type": "uint256"
-      }
-    ],
-    "name": "Transfer",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newAdmin",
-        "type": "tuple"
-      }
-    ],
-    "name": "addCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "addToCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "allowlistedCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "approved", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "approve",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" }
-    ],
-    "name": "balanceOf",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      }
-    ],
-    "name": "balanceOfCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burn",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burnFromCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "newOwner",
-        "type": "tuple"
-      }
-    ],
-    "name": "changeCollectionOwnerCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionAdmins",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionHelperAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionLimits",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNesting",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionOwner",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "collectionProperties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "collectionProperty",
-    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionSponsor",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "confirmCollectionSponsorship",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "contractAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "deleteCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "deleteProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "description",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "getApproved",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "hasCollectionPendingSponsor",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "address", "name": "operator", "type": "address" }
-    ],
-    "name": "isApprovedForAll",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "isOwnerOrAdminCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "address", "name": "to", "type": "address" }],
-    "name": "mint",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          {
-            "components": [
-              {
-                "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 OwnerPieces[]",
-            "name": "owners",
-            "type": "tuple[]"
-          },
-          {
-            "components": [
-              { "internalType": "string", "name": "key", "type": "string" },
-              { "internalType": "bytes", "name": "value", "type": "bytes" }
-            ],
-            "internalType": "struct Property[]",
-            "name": "properties",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct MintTokenData[]",
-        "name": "tokenProperties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "mintBulkCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "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" }
-    ],
-    "name": "mintWithTokenURI",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "name",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "nextTokenId",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "ownerOf",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "ownerOfCross",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "properties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" }
-    ],
-    "name": "property",
-    "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "admin",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeCollectionAdminCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "removeCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "user",
-        "type": "tuple"
-      }
-    ],
-    "name": "removeFromCollectionAllowListCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "safeTransferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "bytes", "name": "data", "type": "bytes" }
-    ],
-    "name": "safeTransferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "operator", "type": "address" },
-      { "internalType": "bool", "name": "approved", "type": "bool" }
-    ],
-    "name": "setApprovalForAll",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
-    ],
-    "name": "setCollectionAccess",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionLimitField",
-            "name": "field",
-            "type": "uint8"
-          },
-          {
-            "components": [
-              { "internalType": "bool", "name": "status", "type": "bool" },
-              { "internalType": "uint256", "name": "value", "type": "uint256" }
-            ],
-            "internalType": "struct OptionUint256",
-            "name": "value",
-            "type": "tuple"
-          }
-        ],
-        "internalType": "struct CollectionLimit",
-        "name": "limit",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionLimit",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
-    "name": "setCollectionMintMode",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          {
-            "internalType": "bool",
-            "name": "collection_admin",
-            "type": "bool"
-          },
-          {
-            "internalType": "address[]",
-            "name": "restricted",
-            "type": "address[]"
-          }
-        ],
-        "internalType": "struct CollectionNestingAndPermission",
-        "name": "collectionNestingAndPermissions",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "properties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setCollectionProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "sponsor",
-        "type": "tuple"
-      }
-    ],
-    "name": "setCollectionSponsorCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "properties",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setProperties",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          {
-            "components": [
-              {
-                "internalType": "enum TokenPermissionField",
-                "name": "code",
-                "type": "uint8"
-              },
-              { "internalType": "bool", "name": "value", "type": "bool" }
-            ],
-            "internalType": "struct PropertyPermission[]",
-            "name": "permissions",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct TokenPropertyPermission[]",
-        "name": "permissions",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "setTokenPropertyPermissions",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "symbol",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "index", "type": "uint256" }
-    ],
-    "name": "tokenByIndex",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "token", "type": "uint256" }
-    ],
-    "name": "tokenContractAddress",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "uint256", "name": "index", "type": "uint256" }
-    ],
-    "name": "tokenOfOwnerByIndex",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "tokenPropertyPermissions",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          {
-            "components": [
-              {
-                "internalType": "enum TokenPermissionField",
-                "name": "code",
-                "type": "uint8"
-              },
-              { "internalType": "bool", "name": "value", "type": "bool" }
-            ],
-            "internalType": "struct PropertyPermission[]",
-            "name": "permissions",
-            "type": "tuple[]"
-          }
-        ],
-        "internalType": "struct TokenPropertyPermission[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "tokenURI",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "totalSupply",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transfer",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "transferFromCross",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "uniqueCollectionType",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/reFungibleDeprecated.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/reFungibleDeprecated.json
+++ /dev/null
@@ -1,200 +0,0 @@
-[
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newAdmin", "type": "address" }
-    ],
-    "name": "addCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "addToCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" }
-    ],
-    "name": "burnFrom",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "string", "name": "key", "type": "string" }],
-    "name": "deleteCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "isOwnerOrAdmin",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "admin", "type": "address" }
-    ],
-    "name": "removeCollectionAdmin",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
-    ],
-    "name": "removeFromCollectionAllowList",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "sponsor", "type": "address" }
-    ],
-    "name": "setCollectionSponsor",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "newOwner", "type": "address" }
-    ],
-    "name": "changeCollectionOwner",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string", "name": "key", "type": "string" }
-    ],
-    "name": "deleteProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" }
-    ],
-    "name": "mintBulk",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      {
-        "components": [
-          { "internalType": "uint256", "name": "field_0", "type": "uint256" },
-          { "internalType": "string", "name": "field_1", "type": "string" }
-        ],
-        "internalType": "struct Tuple0[]",
-        "name": "tokens",
-        "type": "tuple[]"
-      }
-    ],
-    "name": "mintBulkWithTokenURI",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingPermissions",
-    "outputs": [
-      {
-        "components": [
-          {
-            "internalType": "enum CollectionPermissionField",
-            "name": "field",
-            "type": "uint8"
-          },
-          { "internalType": "bool", "name": "value", "type": "bool" }
-        ],
-        "internalType": "struct CollectionNestingPermission[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "collectionNestingRestrictedCollectionIds",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "bool", "name": "token_owner", "type": "bool" },
-          { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }
-        ],
-        "internalType": "struct CollectionNesting",
-        "name": "",
-        "type": "tuple"
-      }
-    ],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bool", "name": "enable", "type": "bool" },
-      {
-        "internalType": "address[]",
-        "name": "collections",
-        "type": "address[]"
-      }
-    ],
-    "name": "setCollectionNesting",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/reFungibleToken.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/reFungibleToken.json
+++ /dev/null
@@ -1,286 +0,0 @@
-[
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "owner",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "spender",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Approval",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
-    "inputs": [
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "from",
-        "type": "address"
-      },
-      {
-        "indexed": true,
-        "internalType": "address",
-        "name": "to",
-        "type": "address"
-      },
-      {
-        "indexed": false,
-        "internalType": "uint256",
-        "name": "value",
-        "type": "uint256"
-      }
-    ],
-    "name": "Transfer",
-    "type": "event"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" },
-      { "internalType": "address", "name": "spender", "type": "address" }
-    ],
-    "name": "allowance",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "spender",
-        "type": "tuple"
-      }
-    ],
-    "name": "allowanceCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "spender", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "approve",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "spender",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "approveCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "owner", "type": "address" }
-    ],
-    "name": "balanceOf",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "owner",
-        "type": "tuple"
-      }
-    ],
-    "name": "balanceOfCross",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "burnFromCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "decimals",
-    "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "name",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "parentToken",
-    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "parentTokenId",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "repartition",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" }
-    ],
-    "name": "supportsInterface",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "symbol",
-    "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "totalSupply",
-    "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transfer",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "address", "name": "to", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "from",
-        "type": "tuple"
-      },
-      {
-        "components": [
-          { "internalType": "address", "name": "eth", "type": "address" },
-          { "internalType": "uint256", "name": "sub", "type": "uint256" }
-        ],
-        "internalType": "struct CrossAddress",
-        "name": "to",
-        "type": "tuple"
-      },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "transferFromCross",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
deletedjs-packages/tests/eth/abi/reFungibleTokenDeprecated.jsondiffbeforeafterboth
--- a/js-packages/tests/eth/abi/reFungibleTokenDeprecated.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
-  {
-    "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "burnFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  }
-]
modifiedjs-packages/tests/eth/allowlist.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/allowlist.test.ts
+++ b/js-packages/tests/eth/allowlist.test.ts
@@ -16,8 +16,8 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets} from '@unique/test-utils/util.js';
-import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util/index.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
+import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '@unique/test-utils/eth/util.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 describe('EVM contract allowlist', () => {
   let donor: IKeyringPair;
deletedjs-packages/tests/eth/api/CollectionHelpers.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/CollectionHelpers.sol
+++ /dev/null
@@ -1,233 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface CollectionHelpersEvents {
-	event CollectionCreated(address indexed owner, address indexed collectionId);
-	event CollectionDestroyed(address indexed collectionId);
-	event CollectionChanged(address indexed collectionId);
-}
-
-/// @title Contract, which allows users to operate with collections
-/// @dev the ERC-165 identifier for this interface is 0x94e5af0d
-interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
-	/// Create a collection
-	/// @return address Address of the newly created collection
-	/// @dev EVM selector for this function is: 0x72b5bea7,
-	///  or in textual repr: createCollection((string,string,string,uint8,uint8,(string,bytes)[],(string,(uint8,bool)[])[],(address,uint256)[],(bool,bool,address[]),(uint8,uint256)[],(address,uint256),uint8))
-	function createCollection(CreateCollectionData memory data) external payable returns (address);
-
-	/// Create an NFT collection
-	/// @param name Name of the collection
-	/// @param description Informative description of the collection
-	/// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
-	/// @return address Address of the newly created collection
-	/// @dev EVM selector for this function is: 0x844af658,
-	///  or in textual repr: createNFTCollection(string,string,string)
-	function createNFTCollection(
-		string memory name,
-		string memory description,
-		string memory tokenPrefix
-	) external payable returns (address);
-
-	// /// Create an NFT collection
-	// /// @param name Name of the collection
-	// /// @param description Informative description of the collection
-	// /// @param tokenPrefix Token prefix to represent the collection tokens in UI and user applications
-	// /// @return address Address of the newly created collection
-	// /// @dev EVM selector for this function is: 0xe34a6844,
-	// ///  or in textual repr: createNonfungibleCollection(string,string,string)
-	// function createNonfungibleCollection(string memory name, string memory description, string memory tokenPrefix) external payable returns (address);
-
-	/// @dev EVM selector for this function is: 0xab173450,
-	///  or in textual repr: createRFTCollection(string,string,string)
-	function createRFTCollection(
-		string memory name,
-		string memory description,
-		string memory tokenPrefix
-	) external payable returns (address);
-
-	/// @dev EVM selector for this function is: 0x7335b79f,
-	///  or in textual repr: createFTCollection(string,uint8,string,string)
-	function createFTCollection(
-		string memory name,
-		uint8 decimals,
-		string memory description,
-		string memory tokenPrefix
-	) external payable returns (address);
-
-	/// @dev EVM selector for this function is: 0x85624258,
-	///  or in textual repr: makeCollectionERC721MetadataCompatible(address,string)
-	function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external;
-
-	/// @dev EVM selector for this function is: 0x564e321f,
-	///  or in textual repr: destroyCollection(address)
-	function destroyCollection(address collectionAddress) external;
-
-	/// Check if a collection exists
-	/// @param collectionAddress Address of the collection in question
-	/// @return bool Does the collection exist?
-	/// @dev EVM selector for this function is: 0xc3de1494,
-	///  or in textual repr: isCollectionExist(address)
-	function isCollectionExist(address collectionAddress) external view returns (bool);
-
-	/// @dev EVM selector for this function is: 0xd23a7ab1,
-	///  or in textual repr: collectionCreationFee()
-	function collectionCreationFee() external view returns (uint256);
-
-	/// Returns address of a collection.
-	/// @param collectionId  - CollectionId  of the collection
-	/// @return eth mirror address of the collection
-	/// @dev EVM selector for this function is: 0x2e716683,
-	///  or in textual repr: collectionAddress(uint32)
-	function collectionAddress(uint32 collectionId) external view returns (address);
-
-	/// Returns collectionId of a collection.
-	/// @param collectionAddress  - Eth address of the collection
-	/// @return collectionId of the collection
-	/// @dev EVM selector for this function is: 0xb5cb7498,
-	///  or in textual repr: collectionId(address)
-	function collectionId(address collectionAddress) external view returns (uint32);
-}
-
-/// Collection properties
-struct CreateCollectionData {
-	/// Collection name
-	string name;
-	/// Collection description
-	string description;
-	/// Token prefix
-	string token_prefix;
-	/// Token type (NFT, FT or RFT)
-	CollectionMode mode;
-	/// Fungible token precision
-	uint8 decimals;
-	/// Custom Properties
-	Property[] properties;
-	/// Permissions for token properties
-	TokenPropertyPermission[] token_property_permissions;
-	/// Collection admins
-	CrossAddress[] admin_list;
-	/// Nesting settings
-	CollectionNestingAndPermission nesting_settings;
-	/// Collection limits
-	CollectionLimitValue[] limits;
-	/// Collection sponsor
-	CrossAddress pending_sponsor;
-	/// Extra collection flags
-	CollectionFlags flags;
-}
-
-type CollectionFlags is uint8;
-
-library CollectionFlagsLib {
-	/// A collection of foreign assets
-	CollectionFlags constant foreignField = CollectionFlags.wrap(128);
-	/// Supports ERC721Metadata
-	CollectionFlags constant erc721metadataField = CollectionFlags.wrap(64);
-	/// External collections can't be managed using `unique` api
-	CollectionFlags constant externalField = CollectionFlags.wrap(1);
-
-	/// Reserved flags
-	function reservedField(uint8 value) public pure returns (CollectionFlags) {
-		require(value < 1 << 5, "out of bound value");
-		return CollectionFlags.wrap(value << 1);
-	}
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimitValue {
-	CollectionLimitField field;
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
-	/// Owner of token can nest tokens under it.
-	bool token_owner;
-	/// Admin of token collection can nest tokens under token.
-	bool collection_admin;
-	/// If set - only tokens from specified collections can be nested.
-	address[] restricted;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
-	/// Token property key.
-	string key;
-	/// Token property permissions.
-	PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
-	/// TokenPermission field.
-	TokenPermissionField code;
-	/// TokenPermission value.
-	bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
-	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
-	Mutable,
-	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
-	TokenOwner,
-	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
-	CollectionAdmin
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// Type of tokens in collection
-enum CollectionMode {
-	/// Nonfungible
-	Nonfungible,
-	/// Fungible
-	Fungible,
-	/// Refungible
-	Refungible
-}
deletedjs-packages/tests/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/ContractHelpers.sol
+++ /dev/null
@@ -1,196 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ContractHelpersEvents {
-	event ContractSponsorSet(address indexed contractAddress, address sponsor);
-	event ContractSponsorshipConfirmed(address indexed contractAddress, address sponsor);
-	event ContractSponsorRemoved(address indexed contractAddress);
-}
-
-/// @title Magic contract, which allows users to reconfigure other contracts
-/// @dev the ERC-165 identifier for this interface is 0x30afad04
-interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents {
-	/// Get user, which deployed specified contract
-	/// @dev May return zero address in case if contract is deployed
-	///  using uniquenetwork evm-migration pallet, or using other terms not
-	///  intended by pallet-evm
-	/// @dev Returns zero address if contract does not exists
-	/// @param contractAddress Contract to get owner of
-	/// @return address Owner of contract
-	/// @dev EVM selector for this function is: 0x5152b14c,
-	///  or in textual repr: contractOwner(address)
-	function contractOwner(address contractAddress) external view returns (address);
-
-	/// Set sponsor.
-	/// @param contractAddress Contract for which a sponsor is being established.
-	/// @param sponsor User address who set as pending sponsor.
-	/// @dev EVM selector for this function is: 0xf01fba93,
-	///  or in textual repr: setSponsor(address,address)
-	function setSponsor(address contractAddress, address sponsor) external;
-
-	/// Set contract as self sponsored.
-	///
-	/// @param contractAddress Contract for which a self sponsoring is being enabled.
-	/// @dev EVM selector for this function is: 0x89f7d9ae,
-	///  or in textual repr: selfSponsoredEnable(address)
-	function selfSponsoredEnable(address contractAddress) external;
-
-	/// Remove sponsor.
-	///
-	/// @param contractAddress Contract for which a sponsorship is being removed.
-	/// @dev EVM selector for this function is: 0xef784250,
-	///  or in textual repr: removeSponsor(address)
-	function removeSponsor(address contractAddress) external;
-
-	/// Confirm sponsorship.
-	///
-	/// @dev Caller must be same that set via [`setSponsor`].
-	///
-	/// @param contractAddress Сontract for which need to confirm sponsorship.
-	/// @dev EVM selector for this function is: 0xabc00001,
-	///  or in textual repr: confirmSponsorship(address)
-	function confirmSponsorship(address contractAddress) external;
-
-	/// Get current sponsor.
-	///
-	/// @param contractAddress The contract for which a sponsor is requested.
-	/// @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: 0x766c4f37,
-	///  or in textual repr: sponsor(address)
-	function sponsor(address contractAddress) external view returns (OptionCrossAddress memory);
-
-	/// Check tat contract has confirmed sponsor.
-	///
-	/// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
-	/// @return **true** if contract has confirmed sponsor.
-	/// @dev EVM selector for this function is: 0x97418603,
-	///  or in textual repr: hasSponsor(address)
-	function hasSponsor(address contractAddress) external view returns (bool);
-
-	/// Check tat contract has pending sponsor.
-	///
-	/// @param contractAddress The contract for which the presence of a pending sponsor is checked.
-	/// @return **true** if contract has pending sponsor.
-	/// @dev EVM selector for this function is: 0x39b9b242,
-	///  or in textual repr: hasPendingSponsor(address)
-	function hasPendingSponsor(address contractAddress) external view returns (bool);
-
-	/// @dev EVM selector for this function is: 0x6027dc61,
-	///  or in textual repr: sponsoringEnabled(address)
-	function sponsoringEnabled(address contractAddress) external view returns (bool);
-
-	/// @dev EVM selector for this function is: 0xfde8a560,
-	///  or in textual repr: setSponsoringMode(address,uint8)
-	function setSponsoringMode(address contractAddress, SponsoringModeT mode) external;
-
-	/// Get current contract sponsoring rate limit
-	/// @param contractAddress Contract to get sponsoring rate limit of
-	/// @return uint32 Amount of blocks between two sponsored transactions
-	/// @dev EVM selector for this function is: 0xf29694d8,
-	///  or in textual repr: sponsoringRateLimit(address)
-	function sponsoringRateLimit(address contractAddress) external view returns (uint32);
-
-	/// Set contract sponsoring rate limit
-	/// @dev Sponsoring rate limit - is a minimum amount of blocks that should
-	///  pass between two sponsored transactions
-	/// @param contractAddress Contract to change sponsoring rate limit of
-	/// @param rateLimit Target rate limit
-	/// @dev Only contract owner can change this setting
-	/// @dev EVM selector for this function is: 0x77b6c908,
-	///  or in textual repr: setSponsoringRateLimit(address,uint32)
-	function setSponsoringRateLimit(address contractAddress, uint32 rateLimit) external;
-
-	/// Set contract sponsoring fee limit
-	/// @dev Sponsoring fee limit - is maximum fee that could be spent by
-	///  single transaction
-	/// @param contractAddress Contract to change sponsoring fee limit of
-	/// @param feeLimit Fee limit
-	/// @dev Only contract owner can change this setting
-	/// @dev EVM selector for this function is: 0x03aed665,
-	///  or in textual repr: setSponsoringFeeLimit(address,uint256)
-	function setSponsoringFeeLimit(address contractAddress, uint256 feeLimit) external;
-
-	/// Get current contract sponsoring fee limit
-	/// @param contractAddress Contract to get sponsoring fee limit of
-	/// @return uint256 Maximum amount of fee that could be spent by single
-	///  transaction
-	/// @dev EVM selector for this function is: 0x75b73606,
-	///  or in textual repr: sponsoringFeeLimit(address)
-	function sponsoringFeeLimit(address contractAddress) external view returns (uint256);
-
-	/// Is specified user present in contract allow list
-	/// @dev Contract owner always implicitly included
-	/// @param contractAddress Contract to check allowlist of
-	/// @param user User to check
-	/// @return bool Is specified users exists in contract allowlist
-	/// @dev EVM selector for this function is: 0x5c658165,
-	///  or in textual repr: allowed(address,address)
-	function allowed(address contractAddress, address user) external view returns (bool);
-
-	/// Toggle user presence in contract allowlist
-	/// @param contractAddress Contract to change allowlist of
-	/// @param user Which user presence should be toggled
-	/// @param isAllowed `true` if user should be allowed to be sponsored
-	///  or call this contract, `false` otherwise
-	/// @dev Only contract owner can change this setting
-	/// @dev EVM selector for this function is: 0x4706cc1c,
-	///  or in textual repr: toggleAllowed(address,address,bool)
-	function toggleAllowed(
-		address contractAddress,
-		address user,
-		bool isAllowed
-	) external;
-
-	/// Is this contract has allowlist access enabled
-	/// @dev Allowlist always can have users, and it is used for two purposes:
-	///  in case of allowlist sponsoring mode, users will be sponsored if they exist in allowlist
-	///  in case of allowlist access enabled, only users from allowlist may call this contract
-	/// @param contractAddress Contract to get allowlist access of
-	/// @return bool Is specified contract has allowlist access enabled
-	/// @dev EVM selector for this function is: 0xc772ef6c,
-	///  or in textual repr: allowlistEnabled(address)
-	function allowlistEnabled(address contractAddress) external view returns (bool);
-
-	/// Toggle contract allowlist access
-	/// @param contractAddress Contract to change allowlist access of
-	/// @param enabled Should allowlist access to be enabled?
-	/// @dev EVM selector for this function is: 0x36de20f5,
-	///  or in textual repr: toggleAllowlist(address,bool)
-	function toggleAllowlist(address contractAddress, bool enabled) external;
-}
-
-/// Available contract sponsoring modes
-enum SponsoringModeT {
-	/// Sponsoring is disabled
-	Disabled,
-	/// Only users from allowlist will be sponsored
-	Allowlisted,
-	/// All users will be sponsored
-	Generous
-}
-
-/// Optional value
-struct OptionCrossAddress {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	CrossAddress value;
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
deletedjs-packages/tests/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/UniqueFungible.sol
+++ /dev/null
@@ -1,510 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
-	// /// Set collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @param value Propery value.
-	// /// @dev EVM selector for this function is: 0x2f073f66,
-	// ///  or in textual repr: setCollectionProperty(string,bytes)
-	// function setCollectionProperty(string memory key, bytes memory value) external;
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Property[] memory properties) external;
-
-	// /// Delete collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x7b7debce,
-	// ///  or in textual repr: deleteCollectionProperty(string)
-	// function deleteCollectionProperty(string memory key) external;
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) external;
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) external view returns (bytes memory);
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
-	// /// Set the sponsor of the collection.
-	// ///
-	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	// ///
-	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	// /// @dev EVM selector for this function is: 0x7623402e,
-	// ///  or in textual repr: setCollectionSponsor(address)
-	// function setCollectionSponsor(address sponsor) external;
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() external view returns (bool);
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() external;
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() external;
-
-	/// Get current sponsor.
-	///
-	/// @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 (CrossAddress memory);
-
-	/// Get current collection limits.
-	///
-	/// @return Array of collection limits
-	/// @dev EVM selector for this function is: 0xf63bc572,
-	///  or in textual repr: collectionLimits()
-	function collectionLimits() external view returns (CollectionLimit[] memory);
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Some limit.
-	/// @dev EVM selector for this function is: 0x2316ee74,
-	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
-	function setCollectionLimit(CollectionLimit memory limit) external;
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() external view returns (address);
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(CrossAddress memory admin) external;
-
-	// /// Add collection admin.
-	// /// @param newAdmin Address of the added administrator.
-	// /// @dev EVM selector for this function is: 0x92e462c7,
-	// ///  or in textual repr: addCollectionAdmin(address)
-	// function addCollectionAdmin(address newAdmin) external;
-
-	// /// Remove collection admin.
-	// ///
-	// /// @param admin Address of the removed administrator.
-	// /// @dev EVM selector for this function is: 0xfafd7b42,
-	// ///  or in textual repr: removeCollectionAdmin(address)
-	// function removeCollectionAdmin(address admin) external;
-
-	/// @dev EVM selector for this function is: 0x0b9f3890,
-	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
-	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	// /// @dev EVM selector for this function is: 0x112d4586,
-	// ///  or in textual repr: setCollectionNesting(bool)
-	// function setCollectionNesting(bool enable) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	// /// @param collections Addresses of collections that will be available for nesting.
-	// /// @dev EVM selector for this function is: 0x64872396,
-	// ///  or in textual repr: setCollectionNesting(bool,address[])
-	// function setCollectionNesting(bool enable, address[] memory collections) external;
-
-	/// @dev EVM selector for this function is: 0x92c660a8,
-	///  or in textual repr: collectionNesting()
-	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
-	// /// Returns nesting for a collection
-	// /// @dev EVM selector for this function is: 0x22d25bfe,
-	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
-	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
-	// /// Returns permissions for a collection
-	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
-	// ///  or in textual repr: collectionNestingPermissions()
-	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(AccessMode mode) external;
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0x91b6df49,
-	///  or in textual repr: allowlistedCross((address,uint256))
-	function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
-	// /// Add the user to the allowed list.
-	// ///
-	// /// @param user Address of a trusted user.
-	// /// @dev EVM selector for this function is: 0x67844fe6,
-	// ///  or in textual repr: addToCollectionAllowList(address)
-	// function addToCollectionAllowList(address user) external;
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(CrossAddress memory user) external;
-
-	// /// Remove the user from the allowed list.
-	// ///
-	// /// @param user Address of a removed user.
-	// /// @dev EVM selector for this function is: 0x85c51acb,
-	// ///  or in textual repr: removeFromCollectionAllowList(address)
-	// function removeFromCollectionAllowList(address user) external;
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) external;
-
-	// /// Check that account is the owner or admin of the collection
-	// ///
-	// /// @param user account to verify
-	// /// @return "true" if account is the owner or admin
-	// /// @dev EVM selector for this function is: 0x9811b0c7,
-	// ///  or in textual repr: isOwnerOrAdmin(address)
-	// function isOwnerOrAdmin(address user) external view returns (bool);
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() external view returns (string memory);
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (CrossAddress memory);
-
-	// /// Changes collection owner to another account
-	// ///
-	// /// @dev Owner can be changed only by current owner
-	// /// @param newOwner new owner account
-	// /// @dev EVM selector for this function is: 0x4f53e226,
-	// ///  or in textual repr: changeCollectionOwner(address)
-	// function changeCollectionOwner(address newOwner) external;
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() external view returns (CrossAddress[] memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0x6496c497,
-	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
-	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
-	/// Access grant for owner and admins. Used as default.
-	Normal,
-	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
-	AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
-	CollectionPermissionField field;
-	bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
-	/// Owner of token can nest tokens under it.
-	TokenOwner,
-	/// Admin of token collection can nest tokens under token.
-	CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
-	bool token_owner;
-	uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
-	/// Owner of token can nest tokens under it.
-	bool token_owner;
-	/// Admin of token collection can nest tokens under token.
-	bool collection_admin;
-	/// If set - only tokens from specified collections can be nested.
-	address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
-	CollectionLimitField field;
-	OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x69d14d3e
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
-	/// @param owner crossAddress The address which owns the funds.
-	/// @param spender crossAddress The address which will spend the funds.
-	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	/// @dev EVM selector for this function is: 0xe0af4bd7,
-	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
-	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
-
-	/// @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(CrossAddress 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(CrossAddress memory spender, uint256 amount) external returns (bool);
-
-	// /// Burn tokens from account
-	// /// @dev Function that burns an `amount` of the tokens of a given account,
-	// /// deducting from the sender's allowance for said account.
-	// /// @param from The account whose tokens will be burnt.
-	// /// @param amount The amount that will be burnt.
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 amount) external returns (bool);
-
-	/// Burn tokens from account
-	/// @dev Function that burns an `amount` of the tokens of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
-
-	/// Mint tokens for multiple accounts.
-	/// @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(AmountForAddress[] memory amounts) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @notice Returns collection helper contract address
-	/// @dev EVM selector for this function is: 0x1896cce6,
-	///  or in textual repr: collectionHelperAddress()
-	function collectionHelperAddress() external view returns (address);
-
-	/// @notice Balance of account
-	/// @param owner An cross address for whom to query the balance
-	/// @return The number of fingibles owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0xec069398,
-	///  or in textual repr: balanceOfCross((address,uint256))
-	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-}
-
-struct AmountForAddress {
-	address to;
-	uint256 amount;
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x40c10f19
-interface ERC20Mintable is Dummy, ERC165 {
-	/// Mint tokens for `to` account.
-	/// @param to account that will receive minted tokens
-	/// @param amount amount of tokens to mint
-	/// @dev EVM selector for this function is: 0x40c10f19,
-	///  or in textual repr: mint(address,uint256)
-	function mint(address to, uint256 amount) external returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() external view returns (uint8);
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
deletedjs-packages/tests/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/UniqueNFT.sol
+++ /dev/null
@@ -1,855 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC721TokenEvent {
-	event TokenChanged(uint256 indexed tokenId);
-}
-
-/// @title A contract that allows to set and delete token properties and change token property permissions.
-/// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
-	// /// @notice Set permissions for token property.
-	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
-	// /// @param key Property key.
-	// /// @param isMutable Permission to mutate property.
-	// /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
-	// /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
-	// /// @dev EVM selector for this function is: 0x222d97fa,
-	// ///  or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
-	// function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
-
-	/// @notice Set permissions for token property.
-	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
-	/// @param permissions Permissions for keys.
-	/// @dev EVM selector for this function is: 0xbd92983a,
-	///  or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
-	function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
-
-	/// @notice Get permissions for token properties.
-	/// @dev EVM selector for this function is: 0xf23d7790,
-	///  or in textual repr: tokenPropertyPermissions()
-	function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
-
-	// /// @notice Set token property value.
-	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
-	// /// @param tokenId ID of the token.
-	// /// @param key Property key.
-	// /// @param value Property value.
-	// /// @dev EVM selector for this function is: 0x1752d67b,
-	// ///  or in textual repr: setProperty(uint256,string,bytes)
-	// function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
-
-	/// @notice Set token properties value.
-	/// @dev Throws error if `msg.sender` has no permission to edit the property.
-	/// @param tokenId ID of the token.
-	/// @param properties settable properties
-	/// @dev EVM selector for this function is: 0x14ed3a6e,
-	///  or in textual repr: setProperties(uint256,(string,bytes)[])
-	function setProperties(uint256 tokenId, Property[] memory properties) external;
-
-	// /// @notice Delete token property value.
-	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
-	// /// @param tokenId ID of the token.
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x066111d1,
-	// ///  or in textual repr: deleteProperty(uint256,string)
-	// function deleteProperty(uint256 tokenId, string memory key) external;
-
-	/// @notice Delete token properties value.
-	/// @dev Throws error if `msg.sender` has no permission to edit the property.
-	/// @param tokenId ID of the token.
-	/// @param keys Properties key.
-	/// @dev EVM selector for this function is: 0xc472d371,
-	///  or in textual repr: deleteProperties(uint256,string[])
-	function deleteProperties(uint256 tokenId, string[] memory keys) external;
-
-	/// @notice Get token property value.
-	/// @dev Throws error if key not found
-	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @return Property value bytes
-	/// @dev EVM selector for this function is: 0x7228c327,
-	///  or in textual repr: property(uint256,string)
-	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
-	/// Token property key.
-	string key;
-	/// Token property permissions.
-	PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
-	/// TokenPermission field.
-	TokenPermissionField code;
-	/// TokenPermission value.
-	bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
-	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
-	Mutable,
-	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
-	TokenOwner,
-	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
-	CollectionAdmin
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
-	// /// Set collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @param value Propery value.
-	// /// @dev EVM selector for this function is: 0x2f073f66,
-	// ///  or in textual repr: setCollectionProperty(string,bytes)
-	// function setCollectionProperty(string memory key, bytes memory value) external;
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Property[] memory properties) external;
-
-	// /// Delete collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x7b7debce,
-	// ///  or in textual repr: deleteCollectionProperty(string)
-	// function deleteCollectionProperty(string memory key) external;
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) external;
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) external view returns (bytes memory);
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
-	// /// Set the sponsor of the collection.
-	// ///
-	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	// ///
-	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	// /// @dev EVM selector for this function is: 0x7623402e,
-	// ///  or in textual repr: setCollectionSponsor(address)
-	// function setCollectionSponsor(address sponsor) external;
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() external view returns (bool);
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() external;
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() external;
-
-	/// Get current sponsor.
-	///
-	/// @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 (CrossAddress memory);
-
-	/// Get current collection limits.
-	///
-	/// @return Array of collection limits
-	/// @dev EVM selector for this function is: 0xf63bc572,
-	///  or in textual repr: collectionLimits()
-	function collectionLimits() external view returns (CollectionLimit[] memory);
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Some limit.
-	/// @dev EVM selector for this function is: 0x2316ee74,
-	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
-	function setCollectionLimit(CollectionLimit memory limit) external;
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() external view returns (address);
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(CrossAddress memory admin) external;
-
-	// /// Add collection admin.
-	// /// @param newAdmin Address of the added administrator.
-	// /// @dev EVM selector for this function is: 0x92e462c7,
-	// ///  or in textual repr: addCollectionAdmin(address)
-	// function addCollectionAdmin(address newAdmin) external;
-
-	// /// Remove collection admin.
-	// ///
-	// /// @param admin Address of the removed administrator.
-	// /// @dev EVM selector for this function is: 0xfafd7b42,
-	// ///  or in textual repr: removeCollectionAdmin(address)
-	// function removeCollectionAdmin(address admin) external;
-
-	/// @dev EVM selector for this function is: 0x0b9f3890,
-	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
-	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	// /// @dev EVM selector for this function is: 0x112d4586,
-	// ///  or in textual repr: setCollectionNesting(bool)
-	// function setCollectionNesting(bool enable) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	// /// @param collections Addresses of collections that will be available for nesting.
-	// /// @dev EVM selector for this function is: 0x64872396,
-	// ///  or in textual repr: setCollectionNesting(bool,address[])
-	// function setCollectionNesting(bool enable, address[] memory collections) external;
-
-	/// @dev EVM selector for this function is: 0x92c660a8,
-	///  or in textual repr: collectionNesting()
-	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
-	// /// Returns nesting for a collection
-	// /// @dev EVM selector for this function is: 0x22d25bfe,
-	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
-	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
-	// /// Returns permissions for a collection
-	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
-	// ///  or in textual repr: collectionNestingPermissions()
-	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(AccessMode mode) external;
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0x91b6df49,
-	///  or in textual repr: allowlistedCross((address,uint256))
-	function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
-	// /// Add the user to the allowed list.
-	// ///
-	// /// @param user Address of a trusted user.
-	// /// @dev EVM selector for this function is: 0x67844fe6,
-	// ///  or in textual repr: addToCollectionAllowList(address)
-	// function addToCollectionAllowList(address user) external;
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(CrossAddress memory user) external;
-
-	// /// Remove the user from the allowed list.
-	// ///
-	// /// @param user Address of a removed user.
-	// /// @dev EVM selector for this function is: 0x85c51acb,
-	// ///  or in textual repr: removeFromCollectionAllowList(address)
-	// function removeFromCollectionAllowList(address user) external;
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) external;
-
-	// /// Check that account is the owner or admin of the collection
-	// ///
-	// /// @param user account to verify
-	// /// @return "true" if account is the owner or admin
-	// /// @dev EVM selector for this function is: 0x9811b0c7,
-	// ///  or in textual repr: isOwnerOrAdmin(address)
-	// function isOwnerOrAdmin(address user) external view returns (bool);
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() external view returns (string memory);
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (CrossAddress memory);
-
-	// /// Changes collection owner to another account
-	// ///
-	// /// @dev Owner can be changed only by current owner
-	// /// @param newOwner new owner account
-	// /// @dev EVM selector for this function is: 0x4f53e226,
-	// ///  or in textual repr: changeCollectionOwner(address)
-	// function changeCollectionOwner(address newOwner) external;
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() external view returns (CrossAddress[] memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0x6496c497,
-	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
-	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
-	/// Access grant for owner and admins. Used as default.
-	Normal,
-	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
-	AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
-	CollectionPermissionField field;
-	bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
-	/// Owner of token can nest tokens under it.
-	TokenOwner,
-	/// Admin of token collection can nest tokens under token.
-	CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
-	bool token_owner;
-	uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
-	/// Owner of token can nest tokens under it.
-	bool token_owner;
-	/// Admin of token collection can nest tokens under token.
-	bool collection_admin;
-	/// If set - only tokens from specified collections can be nested.
-	address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
-	CollectionLimitField field;
-	OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
-interface ERC721Metadata is Dummy, ERC165 {
-	// /// @notice A descriptive name for a collection of NFTs in this contract
-	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
-	// /// @dev EVM selector for this function is: 0x06fdde03,
-	// ///  or in textual repr: name()
-	// function name() external view returns (string memory);
-
-	// /// @notice An abbreviated name for NFTs in this contract
-	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
-	// /// @dev EVM selector for this function is: 0x95d89b41,
-	// ///  or in textual repr: symbol()
-	// function symbol() external view returns (string memory);
-
-	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
-	///
-	/// @dev If the token has a `url` property and it is not empty, it is returned.
-	///  Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
-	///  If the collection property `baseURI` is empty or absent, return "" (empty string)
-	///  otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
-	///  otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
-	///
-	/// @return token's const_metadata
-	/// @dev EVM selector for this function is: 0xc87b56dd,
-	///  or in textual repr: tokenURI(uint256)
-	function tokenURI(uint256 tokenId) external view returns (string memory);
-}
-
-/// @title ERC721 Token that can be irreversibly burned (destroyed).
-/// @dev the ERC-165 identifier for this interface is 0x42966c68
-interface ERC721Burnable is Dummy, ERC165 {
-	/// @notice Burns a specific ERC721 token.
-	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
-	///  operator of the current owner.
-	/// @param tokenId The NFT to approve
-	/// @dev EVM selector for this function is: 0x42966c68,
-	///  or in textual repr: burn(uint256)
-	function burn(uint256 tokenId) external;
-}
-
-/// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
-interface ERC721UniqueMintable is Dummy, ERC165 {
-	/// @notice Function to mint a token.
-	/// @param to The new owner
-	/// @return uint256 The id of the newly minted token
-	/// @dev EVM selector for this function is: 0x6a627842,
-	///  or in textual repr: mint(address)
-	function mint(address to) external returns (uint256);
-
-	// /// @notice Function to mint a token.
-	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
-	// ///  unlike standard, you can't specify it manually
-	// /// @param to The new owner
-	// /// @param tokenId ID of the minted NFT
-	// /// @dev EVM selector for this function is: 0x40c10f19,
-	// ///  or in textual repr: mint(address,uint256)
-	// function mint(address to, uint256 tokenId) external returns (bool);
-
-	/// @notice Function to mint token with the given tokenUri.
-	/// @param to The new owner
-	/// @param tokenUri Token URI that would be stored in the NFT properties
-	/// @return uint256 The id of the newly minted token
-	/// @dev EVM selector for this function is: 0x45c17782,
-	///  or in textual repr: mintWithTokenURI(address,string)
-	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
-	// /// @notice Function to mint token with the given tokenUri.
-	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
-	// ///  unlike standard, you can't specify it manually
-	// /// @param to The new owner
-	// /// @param tokenId ID of the minted NFT
-	// /// @param tokenUri Token URI that would be stored in the NFT properties
-	// /// @dev EVM selector for this function is: 0x50bb4e7f,
-	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
-	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
-
-}
-
-/// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0x9b397d16
-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,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @notice An abbreviated name for NFTs in this contract
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @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);
-
-	// /// Returns the owner (in cross format) of the token.
-	// ///
-	// /// @param tokenId Id for the token.
-	// /// @dev EVM selector for this function is: 0x2b29dace,
-	// ///  or in textual repr: crossOwnerOf(uint256)
-	// function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
-
-	/// Returns the owner (in cross format) of the token.
-	///
-	/// @param tokenId Id for the token.
-	/// @dev EVM selector for this function is: 0xcaa3a4d0,
-	///  or in textual repr: ownerOfCross(uint256)
-	function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
-
-	/// @notice Count all NFTs assigned to an owner
-	/// @param owner An cross address for whom to query the balance
-	/// @return The number of NFTs owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0xec069398,
-	///  or in textual repr: balanceOfCross((address,uint256))
-	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
-	/// Returns the token properties.
-	///
-	/// @param tokenId Id for the token.
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xe07ede7e,
-	///  or in textual repr: properties(uint256,string[])
-	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
-
-	/// @notice Set or reaffirm the approved address for an NFT
-	/// @dev The zero address indicates there is no approved address.
-	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
-	///  operator of the current owner.
-	/// @param approved The new substrate address approved NFT controller
-	/// @param tokenId The NFT to approve
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(CrossAddress memory approved, uint256 tokenId) external;
-
-	/// @notice Transfer ownership of an NFT
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid NFT.
-	/// @param to The new owner
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 tokenId) external;
-
-	/// @notice Transfer ownership of an NFT
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid NFT.
-	/// @param to The new owner
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 tokenId) external;
-
-	/// @notice Transfer ownership of an NFT from cross account address to cross account address
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid NFT.
-	/// @param from Cross acccount address of current owner
-	/// @param to Cross acccount address of new owner
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 tokenId
-	) external;
-
-	// /// @notice Burns a specific ERC721 token.
-	// /// @dev Throws unless `msg.sender` is the current owner or an authorized
-	// ///  operator for this NFT. Throws if `from` is not the current owner. Throws
-	// ///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
-	// /// @param from The current owner of the NFT
-	// /// @param tokenId The NFT to transfer
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 tokenId) external;
-
-	/// @notice Burns a specific ERC721 token.
-	/// @dev Throws unless `msg.sender` is the current owner or an authorized
-	///  operator for this NFT. Throws if `from` is not the current owner. Throws
-	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
-	/// @param from The current owner of the NFT
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
-
-	/// @notice Returns next free NFT ID.
-	/// @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
-	// /// @param to The new owner
-	// /// @param tokenIds IDs of the minted NFTs
-	// /// @dev EVM selector for this function is: 0x44a9945e,
-	// ///  or in textual repr: mintBulk(address,uint256[])
-	// function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
-
-	/// @notice Function to mint a token.
-	/// @param data Array of pairs of token owner and token's properties for minted token
-	/// @dev EVM selector for this function is: 0xab427b0c,
-	///  or in textual repr: mintBulkCross(((address,uint256),(string,bytes)[])[])
-	function mintBulkCross(MintTokenData[] memory data) external returns (bool);
-
-	// /// @notice Function to mint multiple tokens with the given tokenUris.
-	// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
-	// ///  numbers and first number should be obtained with `nextTokenId` method
-	// /// @param to The new owner
-	// /// @param tokens array of pairs of token ID and token URI for minted tokens
-	// /// @dev EVM selector for this function is: 0x36543006,
-	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
-	// function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
-
-	/// @notice Function to mint a 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(CrossAddress memory to, Property[] memory properties) external returns (uint256);
-
-	/// @notice Returns collection helper contract address
-	/// @dev EVM selector for this function is: 0x1896cce6,
-	///  or in textual repr: collectionHelperAddress()
-	function collectionHelperAddress() external view returns (address);
-}
-
-/// Data for creation token with uri.
-struct TokenUri {
-	/// Id of new token.
-	uint256 id;
-	/// Uri of new token.
-	string uri;
-}
-
-/// Token minting parameters
-struct MintTokenData {
-	/// Minted token owner
-	CrossAddress owner;
-	/// Minted token properties
-	Property[] properties;
-}
-
-/// @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
-interface ERC721Enumerable is Dummy, ERC165 {
-	/// @notice Enumerate valid NFTs
-	/// @param index A counter less than `totalSupply()`
-	/// @return The token identifier for the `index`th NFT,
-	///  (sort order not specified)
-	/// @dev EVM selector for this function is: 0x4f6ccce7,
-	///  or in textual repr: tokenByIndex(uint256)
-	function tokenByIndex(uint256 index) external view returns (uint256);
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x2f745c59,
-	///  or in textual repr: tokenOfOwnerByIndex(address,uint256)
-	function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
-	/// @notice Count NFTs tracked by this contract
-	/// @return A count of valid NFTs tracked by this contract, where each one of
-	///  them has an assigned and queryable owner not equal to the zero address
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-}
-
-/// @dev inlined interface
-interface ERC721Events {
-	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
-	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
-	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-}
-
-/// @title ERC-721 Non-Fungible Token Standard
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
-interface ERC721 is Dummy, ERC165, ERC721Events {
-	/// @notice Count all NFTs assigned to an owner
-	/// @dev NFTs assigned to the zero address are considered invalid, and this
-	///  function throws for queries about the zero address.
-	/// @param owner An address for whom to query the balance
-	/// @return The number of NFTs owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @notice Find the owner of an NFT
-	/// @dev NFTs assigned to zero address are considered invalid, and queries
-	///  about them do throw.
-	/// @param tokenId The identifier for an NFT
-	/// @return The address of the owner of the NFT
-	/// @dev EVM selector for this function is: 0x6352211e,
-	///  or in textual repr: ownerOf(uint256)
-	function ownerOf(uint256 tokenId) external view returns (address);
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0xb88d4fde,
-	///  or in textual repr: safeTransferFrom(address,address,uint256,bytes)
-	function safeTransferFrom(
-		address from,
-		address to,
-		uint256 tokenId,
-		bytes memory data
-	) external;
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x42842e0e,
-	///  or in textual repr: safeTransferFrom(address,address,uint256)
-	function safeTransferFrom(
-		address from,
-		address to,
-		uint256 tokenId
-	) external;
-
-	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
-	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
-	///  THEY MAY BE PERMANENTLY LOST
-	/// @dev Throws unless `msg.sender` is the current owner or an authorized
-	///  operator for this NFT. Throws if `from` is not the current owner. Throws
-	///  if `to` is the zero address. Throws if `tokenId` is not a valid NFT.
-	/// @param from The current owner of the NFT
-	/// @param to The new owner
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 tokenId
-	) external;
-
-	/// @notice Set or reaffirm the approved address for an NFT
-	/// @dev The zero address indicates there is no approved address.
-	/// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
-	///  operator of the current owner.
-	/// @param approved The new approved NFT controller
-	/// @param tokenId The NFT to approve
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address approved, uint256 tokenId) external;
-
-	/// @notice Sets or unsets the approval of a given operator.
-	/// The `operator` is allowed to transfer all tokens of the `caller` on their behalf.
-	/// @param operator Operator
-	/// @param approved Should operator status be granted or revoked?
-	/// @dev EVM selector for this function is: 0xa22cb465,
-	///  or in textual repr: setApprovalForAll(address,bool)
-	function setApprovalForAll(address operator, bool approved) external;
-
-	/// @notice Get the approved address for a single NFT
-	/// @dev Throws if `tokenId` is not a valid NFT
-	/// @param tokenId The NFT to find the approved address for
-	/// @return The approved address for this NFT, or the zero address if there is none
-	/// @dev EVM selector for this function is: 0x081812fc,
-	///  or in textual repr: getApproved(uint256)
-	function getApproved(uint256 tokenId) external view returns (address);
-
-	/// @notice Tells whether the given `owner` approves the `operator`.
-	/// @dev EVM selector for this function is: 0xe985e9c5,
-	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
-
-interface UniqueNFT is
-	Dummy,
-	ERC165,
-	ERC721,
-	ERC721Enumerable,
-	ERC721UniqueExtensions,
-	ERC721UniqueMintable,
-	ERC721Burnable,
-	ERC721Metadata,
-	Collection,
-	TokenProperties
-{}
deletedjs-packages/tests/eth/api/UniqueNativeFungible.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/UniqueNativeFungible.sol
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x1313556c
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev EVM selector for this function is: 0xec069398,
-	///  or in textual repr: balanceOfCross((address,uint256))
-	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 amount
-	) external returns (bool);
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// @dev inlined interface
-interface ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() external view returns (uint8);
-
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-}
-
-interface UniqueNativeFungible is Dummy, ERC165, ERC20, ERC20UniqueExtensions {}
deletedjs-packages/tests/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/UniqueRefungible.sol
+++ /dev/null
@@ -1,859 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev inlined interface
-interface ERC721TokenEvent {
-	event TokenChanged(uint256 indexed tokenId);
-}
-
-/// @title A contract that allows to set and delete token properties and change token property permissions.
-/// @dev the ERC-165 identifier for this interface is 0xde0695c2
-interface TokenProperties is Dummy, ERC165, ERC721TokenEvent {
-	// /// @notice Set permissions for token property.
-	// /// @dev Throws error if `msg.sender` is not admin or owner of the collection.
-	// /// @param key Property key.
-	// /// @param isMutable Permission to mutate property.
-	// /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable.
-	// /// @param tokenOwner Permission to mutate property by token owner if property is mutable.
-	// /// @dev EVM selector for this function is: 0x222d97fa,
-	// ///  or in textual repr: setTokenPropertyPermission(string,bool,bool,bool)
-	// function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external;
-
-	/// @notice Set permissions for token property.
-	/// @dev Throws error if `msg.sender` is not admin or owner of the collection.
-	/// @param permissions Permissions for keys.
-	/// @dev EVM selector for this function is: 0xbd92983a,
-	///  or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[])
-	function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external;
-
-	/// @notice Get permissions for token properties.
-	/// @dev EVM selector for this function is: 0xf23d7790,
-	///  or in textual repr: tokenPropertyPermissions()
-	function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory);
-
-	// /// @notice Set token property value.
-	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
-	// /// @param tokenId ID of the token.
-	// /// @param key Property key.
-	// /// @param value Property value.
-	// /// @dev EVM selector for this function is: 0x1752d67b,
-	// ///  or in textual repr: setProperty(uint256,string,bytes)
-	// function setProperty(uint256 tokenId, string memory key, bytes memory value) external;
-
-	/// @notice Set token properties value.
-	/// @dev Throws error if `msg.sender` has no permission to edit the property.
-	/// @param tokenId ID of the token.
-	/// @param properties settable properties
-	/// @dev EVM selector for this function is: 0x14ed3a6e,
-	///  or in textual repr: setProperties(uint256,(string,bytes)[])
-	function setProperties(uint256 tokenId, Property[] memory properties) external;
-
-	// /// @notice Delete token property value.
-	// /// @dev Throws error if `msg.sender` has no permission to edit the property.
-	// /// @param tokenId ID of the token.
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x066111d1,
-	// ///  or in textual repr: deleteProperty(uint256,string)
-	// function deleteProperty(uint256 tokenId, string memory key) external;
-
-	/// @notice Delete token properties value.
-	/// @dev Throws error if `msg.sender` has no permission to edit the property.
-	/// @param tokenId ID of the token.
-	/// @param keys Properties key.
-	/// @dev EVM selector for this function is: 0xc472d371,
-	///  or in textual repr: deleteProperties(uint256,string[])
-	function deleteProperties(uint256 tokenId, string[] memory keys) external;
-
-	/// @notice Get token property value.
-	/// @dev Throws error if key not found
-	/// @param tokenId ID of the token.
-	/// @param key Property key.
-	/// @return Property value bytes
-	/// @dev EVM selector for this function is: 0x7228c327,
-	///  or in textual repr: property(uint256,string)
-	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
-}
-
-/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
-struct Property {
-	string key;
-	bytes value;
-}
-
-/// Ethereum representation of Token Property Permissions.
-struct TokenPropertyPermission {
-	/// Token property key.
-	string key;
-	/// Token property permissions.
-	PropertyPermission[] permissions;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
-struct PropertyPermission {
-	/// TokenPermission field.
-	TokenPermissionField code;
-	/// TokenPermission value.
-	bool value;
-}
-
-/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
-enum TokenPermissionField {
-	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
-	Mutable,
-	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
-	TokenOwner,
-	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
-	CollectionAdmin
-}
-
-/// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0xb34d97e9
-interface Collection is Dummy, ERC165 {
-	// /// Set collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @param value Propery value.
-	// /// @dev EVM selector for this function is: 0x2f073f66,
-	// ///  or in textual repr: setCollectionProperty(string,bytes)
-	// function setCollectionProperty(string memory key, bytes memory value) external;
-
-	/// Set collection properties.
-	///
-	/// @param properties Vector of properties key/value pair.
-	/// @dev EVM selector for this function is: 0x50b26b2a,
-	///  or in textual repr: setCollectionProperties((string,bytes)[])
-	function setCollectionProperties(Property[] memory properties) external;
-
-	// /// Delete collection property.
-	// ///
-	// /// @param key Property key.
-	// /// @dev EVM selector for this function is: 0x7b7debce,
-	// ///  or in textual repr: deleteCollectionProperty(string)
-	// function deleteCollectionProperty(string memory key) external;
-
-	/// Delete collection properties.
-	///
-	/// @param keys Properties keys.
-	/// @dev EVM selector for this function is: 0xee206ee3,
-	///  or in textual repr: deleteCollectionProperties(string[])
-	function deleteCollectionProperties(string[] memory keys) external;
-
-	/// Get collection property.
-	///
-	/// @dev Throws error if key not found.
-	///
-	/// @param key Property key.
-	/// @return bytes The property corresponding to the key.
-	/// @dev EVM selector for this function is: 0xcf24fd6d,
-	///  or in textual repr: collectionProperty(string)
-	function collectionProperty(string memory key) external view returns (bytes memory);
-
-	/// Get collection properties.
-	///
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0x285fb8e6,
-	///  or in textual repr: collectionProperties(string[])
-	function collectionProperties(string[] memory keys) external view returns (Property[] memory);
-
-	// /// Set the sponsor of the collection.
-	// ///
-	// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	// ///
-	// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
-	// /// @dev EVM selector for this function is: 0x7623402e,
-	// ///  or in textual repr: setCollectionSponsor(address)
-	// function setCollectionSponsor(address sponsor) external;
-
-	/// Set the sponsor of the collection.
-	///
-	/// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor.
-	///
-	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
-	/// @dev EVM selector for this function is: 0x84a1d5a8,
-	///  or in textual repr: setCollectionSponsorCross((address,uint256))
-	function setCollectionSponsorCross(CrossAddress memory sponsor) external;
-
-	/// Whether there is a pending sponsor.
-	/// @dev EVM selector for this function is: 0x058ac185,
-	///  or in textual repr: hasCollectionPendingSponsor()
-	function hasCollectionPendingSponsor() external view returns (bool);
-
-	/// Collection sponsorship confirmation.
-	///
-	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	/// @dev EVM selector for this function is: 0x3c50e97a,
-	///  or in textual repr: confirmCollectionSponsorship()
-	function confirmCollectionSponsorship() external;
-
-	/// Remove collection sponsor.
-	/// @dev EVM selector for this function is: 0x6e0326a3,
-	///  or in textual repr: removeCollectionSponsor()
-	function removeCollectionSponsor() external;
-
-	/// Get current sponsor.
-	///
-	/// @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 (CrossAddress memory);
-
-	/// Get current collection limits.
-	///
-	/// @return Array of collection limits
-	/// @dev EVM selector for this function is: 0xf63bc572,
-	///  or in textual repr: collectionLimits()
-	function collectionLimits() external view returns (CollectionLimit[] memory);
-
-	/// Set limits for the collection.
-	/// @dev Throws error if limit not found.
-	/// @param limit Some limit.
-	/// @dev EVM selector for this function is: 0x2316ee74,
-	///  or in textual repr: setCollectionLimit((uint8,(bool,uint256)))
-	function setCollectionLimit(CollectionLimit memory limit) external;
-
-	/// Get contract address.
-	/// @dev EVM selector for this function is: 0xf6b4dfb4,
-	///  or in textual repr: contractAddress()
-	function contractAddress() external view returns (address);
-
-	/// Add collection admin.
-	/// @param newAdmin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x859aa7d6,
-	///  or in textual repr: addCollectionAdminCross((address,uint256))
-	function addCollectionAdminCross(CrossAddress memory newAdmin) external;
-
-	/// Remove collection admin.
-	/// @param admin Cross account administrator address.
-	/// @dev EVM selector for this function is: 0x6c0cd173,
-	///  or in textual repr: removeCollectionAdminCross((address,uint256))
-	function removeCollectionAdminCross(CrossAddress memory admin) external;
-
-	// /// Add collection admin.
-	// /// @param newAdmin Address of the added administrator.
-	// /// @dev EVM selector for this function is: 0x92e462c7,
-	// ///  or in textual repr: addCollectionAdmin(address)
-	// function addCollectionAdmin(address newAdmin) external;
-
-	// /// Remove collection admin.
-	// ///
-	// /// @param admin Address of the removed administrator.
-	// /// @dev EVM selector for this function is: 0xfafd7b42,
-	// ///  or in textual repr: removeCollectionAdmin(address)
-	// function removeCollectionAdmin(address admin) external;
-
-	/// @dev EVM selector for this function is: 0x0b9f3890,
-	///  or in textual repr: setCollectionNesting((bool,bool,address[]))
-	function setCollectionNesting(CollectionNestingAndPermission memory collectionNestingAndPermissions) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
-	// /// @dev EVM selector for this function is: 0x112d4586,
-	// ///  or in textual repr: setCollectionNesting(bool)
-	// function setCollectionNesting(bool enable) external;
-
-	// /// Toggle accessibility of collection nesting.
-	// ///
-	// /// @param enable If "true" degenerates to nesting: {OwnerRestricted: [1, 2, 3]} else to nesting: 'Disabled'
-	// /// @param collections Addresses of collections that will be available for nesting.
-	// /// @dev EVM selector for this function is: 0x64872396,
-	// ///  or in textual repr: setCollectionNesting(bool,address[])
-	// function setCollectionNesting(bool enable, address[] memory collections) external;
-
-	/// @dev EVM selector for this function is: 0x92c660a8,
-	///  or in textual repr: collectionNesting()
-	function collectionNesting() external view returns (CollectionNestingAndPermission memory);
-
-	// /// Returns nesting for a collection
-	// /// @dev EVM selector for this function is: 0x22d25bfe,
-	// ///  or in textual repr: collectionNestingRestrictedCollectionIds()
-	// function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory);
-
-	// /// Returns permissions for a collection
-	// /// @dev EVM selector for this function is: 0x5b2eaf4b,
-	// ///  or in textual repr: collectionNestingPermissions()
-	// function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory);
-
-	/// Set the collection access method.
-	/// @param mode Access mode
-	/// @dev EVM selector for this function is: 0x41835d4c,
-	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(AccessMode mode) external;
-
-	/// Checks that user allowed to operate with collection.
-	///
-	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0x91b6df49,
-	///  or in textual repr: allowlistedCross((address,uint256))
-	function allowlistedCross(CrossAddress memory user) external view returns (bool);
-
-	// /// Add the user to the allowed list.
-	// ///
-	// /// @param user Address of a trusted user.
-	// /// @dev EVM selector for this function is: 0x67844fe6,
-	// ///  or in textual repr: addToCollectionAllowList(address)
-	// function addToCollectionAllowList(address user) external;
-
-	/// Add user to allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0xa0184a3a,
-	///  or in textual repr: addToCollectionAllowListCross((address,uint256))
-	function addToCollectionAllowListCross(CrossAddress memory user) external;
-
-	// /// Remove the user from the allowed list.
-	// ///
-	// /// @param user Address of a removed user.
-	// /// @dev EVM selector for this function is: 0x85c51acb,
-	// ///  or in textual repr: removeFromCollectionAllowList(address)
-	// function removeFromCollectionAllowList(address user) external;
-
-	/// Remove user from allowed list.
-	///
-	/// @param user User cross account address.
-	/// @dev EVM selector for this function is: 0x09ba452a,
-	///  or in textual repr: removeFromCollectionAllowListCross((address,uint256))
-	function removeFromCollectionAllowListCross(CrossAddress memory user) external;
-
-	/// Switch permission for minting.
-	///
-	/// @param mode Enable if "true".
-	/// @dev EVM selector for this function is: 0x00018e84,
-	///  or in textual repr: setCollectionMintMode(bool)
-	function setCollectionMintMode(bool mode) external;
-
-	// /// Check that account is the owner or admin of the collection
-	// ///
-	// /// @param user account to verify
-	// /// @return "true" if account is the owner or admin
-	// /// @dev EVM selector for this function is: 0x9811b0c7,
-	// ///  or in textual repr: isOwnerOrAdmin(address)
-	// function isOwnerOrAdmin(address user) external view returns (bool);
-
-	/// Check that account is the owner or admin of the collection
-	///
-	/// @param user User cross account to verify
-	/// @return "true" if account is the owner or admin
-	/// @dev EVM selector for this function is: 0x3e75a905,
-	///  or in textual repr: isOwnerOrAdminCross((address,uint256))
-	function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool);
-
-	/// Returns collection type
-	///
-	/// @return `Fungible` or `NFT` or `ReFungible`
-	/// @dev EVM selector for this function is: 0xd34b55b8,
-	///  or in textual repr: uniqueCollectionType()
-	function uniqueCollectionType() external view returns (string memory);
-
-	/// Get collection owner.
-	///
-	/// @return Tuble with sponsor address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0xdf727d3b,
-	///  or in textual repr: collectionOwner()
-	function collectionOwner() external view returns (CrossAddress memory);
-
-	// /// Changes collection owner to another account
-	// ///
-	// /// @dev Owner can be changed only by current owner
-	// /// @param newOwner new owner account
-	// /// @dev EVM selector for this function is: 0x4f53e226,
-	// ///  or in textual repr: changeCollectionOwner(address)
-	// function changeCollectionOwner(address newOwner) external;
-
-	/// Get collection administrators
-	///
-	/// @return Vector of tuples with admins address and his substrate mirror.
-	/// If address is canonical then substrate mirror is zero and vice versa.
-	/// @dev EVM selector for this function is: 0x5813216b,
-	///  or in textual repr: collectionAdmins()
-	function collectionAdmins() external view returns (CrossAddress[] memory);
-
-	/// Changes collection owner to another account
-	///
-	/// @dev Owner can be changed only by current owner
-	/// @param newOwner new owner cross account
-	/// @dev EVM selector for this function is: 0x6496c497,
-	///  or in textual repr: changeCollectionOwnerCross((address,uint256))
-	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
-enum AccessMode {
-	/// Access grant for owner and admins. Used as default.
-	Normal,
-	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
-	AllowList
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
-struct CollectionNestingPermission {
-	CollectionPermissionField field;
-	bool value;
-}
-
-/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
-enum CollectionPermissionField {
-	/// Owner of token can nest tokens under it.
-	TokenOwner,
-	/// Admin of token collection can nest tokens under token.
-	CollectionAdmin
-}
-
-/// Nested collections.
-struct CollectionNesting {
-	bool token_owner;
-	uint256[] ids;
-}
-
-/// Nested collections and permissions
-struct CollectionNestingAndPermission {
-	/// Owner of token can nest tokens under it.
-	bool token_owner;
-	/// Admin of token collection can nest tokens under token.
-	bool collection_admin;
-	/// If set - only tokens from specified collections can be nested.
-	address[] restricted;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
-struct CollectionLimit {
-	CollectionLimitField field;
-	OptionUint256 value;
-}
-
-/// Optional value
-struct OptionUint256 {
-	/// Shows the status of accessibility of value
-	bool status;
-	/// Actual value if `status` is true
-	uint256 value;
-}
-
-/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
-enum CollectionLimitField {
-	/// How many tokens can a user have on one account.
-	AccountTokenOwnership,
-	/// How many bytes of data are available for sponsorship.
-	SponsoredDataSize,
-	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
-	SponsoredDataRateLimit,
-	/// How many tokens can be mined into this collection.
-	TokenLimit,
-	/// Timeouts for transfer sponsoring.
-	SponsorTransferTimeout,
-	/// Timeout for sponsoring an approval in passed blocks.
-	SponsorApproveTimeout,
-	/// Whether the collection owner of the collection can send tokens (which belong to other users).
-	OwnerCanTransfer,
-	/// Can the collection owner burn other people's tokens.
-	OwnerCanDestroy,
-	/// Is it possible to send tokens from this collection between users.
-	TransferEnabled
-}
-
-/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
-/// @dev See https://eips.ethereum.org/EIPS/eip-721
-/// @dev the ERC-165 identifier for this interface is 0x5b5e139f
-interface ERC721Metadata is Dummy, ERC165 {
-	// /// @notice A descriptive name for a collection of NFTs in this contract
-	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
-	// /// @dev EVM selector for this function is: 0x06fdde03,
-	// ///  or in textual repr: name()
-	// function name() external view returns (string memory);
-
-	// /// @notice An abbreviated name for NFTs in this contract
-	// /// @dev real implementation of this function lies in `ERC721UniqueExtensions`
-	// /// @dev EVM selector for this function is: 0x95d89b41,
-	// ///  or in textual repr: symbol()
-	// function symbol() external view returns (string memory);
-
-	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
-	///
-	/// @dev If the token has a `url` property and it is not empty, it is returned.
-	///  Else If the collection does not have a property with key `schemaName` or its value is not equal to `ERC721Metadata`, it return an error `tokenURI not set`.
-	///  If the collection property `baseURI` is empty or absent, return "" (empty string)
-	///  otherwise, if token property `suffix` present and is non-empty, return concatenation of baseURI and suffix
-	///  otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings).
-	///
-	/// @return token's const_metadata
-	/// @dev EVM selector for this function is: 0xc87b56dd,
-	///  or in textual repr: tokenURI(uint256)
-	function tokenURI(uint256 tokenId) external view returns (string memory);
-}
-
-/// @title ERC721 Token that can be irreversibly burned (destroyed).
-/// @dev the ERC-165 identifier for this interface is 0x42966c68
-interface ERC721Burnable is Dummy, ERC165 {
-	/// @notice Burns a specific ERC721 token.
-	/// @dev Throws unless `msg.sender` is the current RFT owner, or an authorized
-	///  operator of the current owner.
-	/// @param tokenId The RFT to approve
-	/// @dev EVM selector for this function is: 0x42966c68,
-	///  or in textual repr: burn(uint256)
-	function burn(uint256 tokenId) external;
-}
-
-/// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
-interface ERC721UniqueMintable is Dummy, ERC165 {
-	/// @notice Function to mint a token.
-	/// @param to The new owner
-	/// @return uint256 The id of the newly minted token
-	/// @dev EVM selector for this function is: 0x6a627842,
-	///  or in textual repr: mint(address)
-	function mint(address to) external returns (uint256);
-
-	// /// @notice Function to mint a token.
-	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
-	// ///  unlike standard, you can't specify it manually
-	// /// @param to The new owner
-	// /// @param tokenId ID of the minted RFT
-	// /// @dev EVM selector for this function is: 0x40c10f19,
-	// ///  or in textual repr: mint(address,uint256)
-	// function mint(address to, uint256 tokenId) external returns (bool);
-
-	/// @notice Function to mint token with the given tokenUri.
-	/// @param to The new owner
-	/// @param tokenUri Token URI that would be stored in the NFT properties
-	/// @return uint256 The id of the newly minted token
-	/// @dev EVM selector for this function is: 0x45c17782,
-	///  or in textual repr: mintWithTokenURI(address,string)
-	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
-	// /// @notice Function to mint token with the given tokenUri.
-	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
-	// ///  unlike standard, you can't specify it manually
-	// /// @param to The new owner
-	// /// @param tokenId ID of the minted RFT
-	// /// @param tokenUri Token URI that would be stored in the RFT properties
-	// /// @dev EVM selector for this function is: 0x50bb4e7f,
-	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
-	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
-
-}
-
-/// @title Unique extensions for ERC721.
-/// @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,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @notice An abbreviated name for NFTs in this contract
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @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);
-
-	// /// Returns the owner (in cross format) of the token.
-	// ///
-	// /// @param tokenId Id for the token.
-	// /// @dev EVM selector for this function is: 0x2b29dace,
-	// ///  or in textual repr: crossOwnerOf(uint256)
-	// function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory);
-
-	/// Returns the owner (in cross format) of the token.
-	///
-	/// @param tokenId Id for the token.
-	/// @dev EVM selector for this function is: 0xcaa3a4d0,
-	///  or in textual repr: ownerOfCross(uint256)
-	function ownerOfCross(uint256 tokenId) external view returns (CrossAddress memory);
-
-	/// @notice Count all RFTs assigned to an owner
-	/// @param owner An cross address for whom to query the balance
-	/// @return The number of RFTs owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0xec069398,
-	///  or in textual repr: balanceOfCross((address,uint256))
-	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
-	/// Returns the token properties.
-	///
-	/// @param tokenId Id for the token.
-	/// @param keys Properties keys. Empty keys for all propertyes.
-	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xe07ede7e,
-	///  or in textual repr: properties(uint256,string[])
-	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
-
-	/// @notice Transfer ownership of an RFT
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid RFT.
-	///  Throws if RFT pieces have multiple owners.
-	/// @param to The new owner
-	/// @param tokenId The RFT to transfer
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 tokenId) external;
-
-	/// @notice Transfer ownership of an RFT
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid RFT.
-	///  Throws if RFT pieces have multiple owners.
-	/// @param to The new owner
-	/// @param tokenId The RFT to transfer
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 tokenId) external;
-
-	/// @notice Transfer ownership of an RFT
-	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
-	///  is the zero address. Throws if `tokenId` is not a valid RFT.
-	///  Throws if RFT pieces have multiple owners.
-	/// @param to The new owner
-	/// @param tokenId The RFT to transfer
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 tokenId
-	) external;
-
-	// /// @notice Burns a specific ERC721 token.
-	// /// @dev Throws unless `msg.sender` is the current owner or an authorized
-	// ///  operator for this RFT. Throws if `from` is not the current owner. Throws
-	// ///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
-	// ///  Throws if RFT pieces have multiple owners.
-	// /// @param from The current owner of the RFT
-	// /// @param tokenId The RFT to transfer
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 tokenId) external;
-
-	/// @notice Burns a specific ERC721 token.
-	/// @dev Throws unless `msg.sender` is the current owner or an authorized
-	///  operator for this RFT. Throws if `from` is not the current owner. Throws
-	///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
-	///  Throws if RFT pieces have multiple owners.
-	/// @param from The current owner of the RFT
-	/// @param tokenId The RFT to transfer
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 tokenId) external;
-
-	/// @notice Returns next free RFT ID.
-	/// @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
-	// /// @param to The new owner
-	// /// @param tokenIds IDs of the minted RFTs
-	// /// @dev EVM selector for this function is: 0x44a9945e,
-	// ///  or in textual repr: mintBulk(address,uint256[])
-	// function mintBulk(address to, uint256[] memory tokenIds) external returns (bool);
-
-	/// @notice Function to mint a token.
-	/// @param tokenProperties Properties of minted token
-	/// @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.
-	// /// @dev `tokenIds` is array of pairs of token ID and token URI. Token IDs should be consecutive
-	// ///  numbers and first number should be obtained with `nextTokenId` method
-	// /// @param to The new owner
-	// /// @param tokens array of pairs of token ID and token URI for minted tokens
-	// /// @dev EVM selector for this function is: 0x36543006,
-	// ///  or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[])
-	// function mintBulkWithTokenURI(address to, TokenUri[] memory tokens) external returns (bool);
-
-	/// @notice Function to mint a 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(CrossAddress memory to, Property[] memory properties) external returns (uint256);
-
-	/// Returns EVM address for refungible token
-	///
-	/// @param token ID of the token
-	/// @dev EVM selector for this function is: 0xab76fac6,
-	///  or in textual repr: tokenContractAddress(uint256)
-	function tokenContractAddress(uint256 token) external view returns (address);
-
-	/// @notice Returns collection helper contract address
-	/// @dev EVM selector for this function is: 0x1896cce6,
-	///  or in textual repr: collectionHelperAddress()
-	function collectionHelperAddress() external view returns (address);
-}
-
-/// Data for creation token with uri.
-struct TokenUri {
-	/// Id of new token.
-	uint256 id;
-	/// Uri of new token.
-	string uri;
-}
-
-/// Token minting parameters
-struct MintTokenData {
-	/// 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
-interface ERC721Enumerable is Dummy, ERC165 {
-	/// @notice Enumerate valid RFTs
-	/// @param index A counter less than `totalSupply()`
-	/// @return The token identifier for the `index`th NFT,
-	///  (sort order not specified)
-	/// @dev EVM selector for this function is: 0x4f6ccce7,
-	///  or in textual repr: tokenByIndex(uint256)
-	function tokenByIndex(uint256 index) external view returns (uint256);
-
-	/// Not implemented
-	/// @dev EVM selector for this function is: 0x2f745c59,
-	///  or in textual repr: tokenOfOwnerByIndex(address,uint256)
-	function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
-
-	/// @notice Count RFTs tracked by this contract
-	/// @return A count of valid RFTs tracked by this contract, where each one of
-	///  them has an assigned and queryable owner not equal to the zero address
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-}
-
-/// @dev inlined interface
-interface ERC721Events {
-	event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
-	event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
-	event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
-}
-
-/// @title ERC-721 Non-Fungible Token Standard
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
-interface ERC721 is Dummy, ERC165, ERC721Events {
-	/// @notice Count all RFTs assigned to an owner
-	/// @dev RFTs assigned to the zero address are considered invalid, and this
-	///  function throws for queries about the zero address.
-	/// @param owner An address for whom to query the balance
-	/// @return The number of RFTs owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @notice Find the owner of an RFT
-	/// @dev RFTs assigned to zero address are considered invalid, and queries
-	///  about them do throw.
-	///  Returns special 0xffffffffffffffffffffffffffffffffffffffff address for
-	///  the tokens that are partially owned.
-	/// @param tokenId The identifier for an RFT
-	/// @return The address of the owner of the RFT
-	/// @dev EVM selector for this function is: 0x6352211e,
-	///  or in textual repr: ownerOf(uint256)
-	function ownerOf(uint256 tokenId) external view returns (address);
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0xb88d4fde,
-	///  or in textual repr: safeTransferFrom(address,address,uint256,bytes)
-	function safeTransferFrom(
-		address from,
-		address to,
-		uint256 tokenId,
-		bytes memory data
-	) external;
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x42842e0e,
-	///  or in textual repr: safeTransferFrom(address,address,uint256)
-	function safeTransferFrom(
-		address from,
-		address to,
-		uint256 tokenId
-	) external;
-
-	/// @notice Transfer ownership of an RFT -- THE CALLER IS RESPONSIBLE
-	///  TO CONFIRM THAT `to` IS CAPABLE OF RECEIVING NFTS OR ELSE
-	///  THEY MAY BE PERMANENTLY LOST
-	/// @dev Throws unless `msg.sender` is the current owner or an authorized
-	///  operator for this RFT. Throws if `from` is not the current owner. Throws
-	///  if `to` is the zero address. Throws if `tokenId` is not a valid RFT.
-	///  Throws if RFT pieces have multiple owners.
-	/// @param from The current owner of the NFT
-	/// @param to The new owner
-	/// @param tokenId The NFT to transfer
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 tokenId
-	) external;
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address approved, uint256 tokenId) external;
-
-	/// @notice Sets or unsets the approval of a given operator.
-	///  The `operator` is allowed to transfer all token pieces of the `caller` on their behalf.
-	/// @param operator Operator
-	/// @param approved Should operator status be granted or revoked?
-	/// @dev EVM selector for this function is: 0xa22cb465,
-	///  or in textual repr: setApprovalForAll(address,bool)
-	function setApprovalForAll(address operator, bool approved) external;
-
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x081812fc,
-	///  or in textual repr: getApproved(uint256)
-	function getApproved(uint256 tokenId) external view returns (address);
-
-	/// @notice Tells whether the given `owner` approves the `operator`.
-	/// @dev EVM selector for this function is: 0xe985e9c5,
-	///  or in textual repr: isApprovedForAll(address,address)
-	function isApprovedForAll(address owner, address operator) external view returns (bool);
-}
-
-interface UniqueRefungible is
-	Dummy,
-	ERC165,
-	ERC721,
-	ERC721Enumerable,
-	ERC721UniqueExtensions,
-	ERC721UniqueMintable,
-	ERC721Burnable,
-	ERC721Metadata,
-	Collection,
-	TokenProperties
-{}
deletedjs-packages/tests/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/js-packages/tests/eth/api/UniqueRefungibleToken.sol
+++ /dev/null
@@ -1,181 +0,0 @@
-// SPDX-License-Identifier: OTHER
-// This code is automatically generated
-
-pragma solidity >=0.8.0 <0.9.0;
-
-/// @dev common stubs holder
-interface Dummy {
-
-}
-
-interface ERC165 is Dummy {
-	function supportsInterface(bytes4 interfaceID) external view returns (bool);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0x5755c3f2
-interface ERC1633 is Dummy, ERC165 {
-	/// @dev EVM selector for this function is: 0x80a54001,
-	///  or in textual repr: parentToken()
-	function parentToken() external view returns (address);
-
-	/// @dev EVM selector for this function is: 0xd7f083f3,
-	///  or in textual repr: parentTokenId()
-	function parentTokenId() external view returns (uint256);
-}
-
-/// @dev the ERC-165 identifier for this interface is 0xedd3a564
-interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
-	/// @param owner crossAddress The address which owns the funds.
-	/// @param spender crossAddress The address which will spend the funds.
-	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	/// @dev EVM selector for this function is: 0xe0af4bd7,
-	///  or in textual repr: allowanceCross((address,uint256),(address,uint256))
-	function allowanceCross(CrossAddress memory owner, CrossAddress memory spender) external view returns (uint256);
-
-	// /// @dev Function that burns an amount of the token of a given account,
-	// /// deducting from the sender's allowance for said account.
-	// /// @param from The account whose tokens will be burnt.
-	// /// @param amount The amount that will be burnt.
-	// /// @dev EVM selector for this function is: 0x79cc6790,
-	// ///  or in textual repr: burnFrom(address,uint256)
-	// function burnFrom(address from, uint256 amount) external returns (bool);
-
-	/// @dev Function that burns an amount of the token of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0xbb2f5a58,
-	///  or in textual repr: burnFromCross((address,uint256),uint256)
-	function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool);
-
-	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
-	/// Beware that changing an allowance with this method brings the risk that someone may use both the old
-	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
-	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
-	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
-	/// @param spender The crossaccount which will spend the funds.
-	/// @param amount The amount of tokens to be spent.
-	/// @dev EVM selector for this function is: 0x0ecd0ab0,
-	///  or in textual repr: approveCross((address,uint256),uint256)
-	function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool);
-
-	/// @notice Balance of account
-	/// @param owner An cross address for whom to query the balance
-	/// @return The number of fingibles owned by `owner`, possibly zero
-	/// @dev EVM selector for this function is: 0xec069398,
-	///  or in textual repr: balanceOfCross((address,uint256))
-	function balanceOfCross(CrossAddress memory owner) external view returns (uint256);
-
-	/// @dev Function that changes total amount of the tokens.
-	///  Throws if `msg.sender` doesn't owns all of the tokens.
-	/// @param amount New total amount of the tokens.
-	/// @dev EVM selector for this function is: 0xd2418ca7,
-	///  or in textual repr: repartition(uint256)
-	function repartition(uint256 amount) external returns (bool);
-
-	/// @dev Transfer token for a specified address
-	/// @param to The crossaccount to transfer to.
-	/// @param amount The amount to be transferred.
-	/// @dev EVM selector for this function is: 0x2ada85ff,
-	///  or in textual repr: transferCross((address,uint256),uint256)
-	function transferCross(CrossAddress memory to, uint256 amount) external returns (bool);
-
-	/// @dev Transfer tokens from one address to another
-	/// @param from The address which you want to send tokens from
-	/// @param to The address which you want to transfer to
-	/// @param amount the amount of tokens to be transferred
-	/// @dev EVM selector for this function is: 0xd5cf430b,
-	///  or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256)
-	function transferFromCross(
-		CrossAddress memory from,
-		CrossAddress memory to,
-		uint256 amount
-	) external returns (bool);
-}
-
-/// Cross account struct
-struct CrossAddress {
-	address eth;
-	uint256 sub;
-}
-
-/// @dev inlined interface
-interface ERC20Events {
-	event Transfer(address indexed from, address indexed to, uint256 value);
-	event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-/// @title Standard ERC20 token
-///
-/// @dev Implementation of the basic standard token.
-/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
-interface ERC20 is Dummy, ERC165, ERC20Events {
-	/// @return the name of the token.
-	/// @dev EVM selector for this function is: 0x06fdde03,
-	///  or in textual repr: name()
-	function name() external view returns (string memory);
-
-	/// @return the symbol of the token.
-	/// @dev EVM selector for this function is: 0x95d89b41,
-	///  or in textual repr: symbol()
-	function symbol() external view returns (string memory);
-
-	/// @dev Total number of tokens in existence
-	/// @dev EVM selector for this function is: 0x18160ddd,
-	///  or in textual repr: totalSupply()
-	function totalSupply() external view returns (uint256);
-
-	/// @dev Not supported
-	/// @dev EVM selector for this function is: 0x313ce567,
-	///  or in textual repr: decimals()
-	function decimals() external view returns (uint8);
-
-	/// @dev Gets the balance of the specified address.
-	/// @param owner The address to query the balance of.
-	/// @return An uint256 representing the amount owned by the passed address.
-	/// @dev EVM selector for this function is: 0x70a08231,
-	///  or in textual repr: balanceOf(address)
-	function balanceOf(address owner) external view returns (uint256);
-
-	/// @dev Transfer token for a specified address
-	/// @param to The address to transfer to.
-	/// @param amount The amount to be transferred.
-	/// @dev EVM selector for this function is: 0xa9059cbb,
-	///  or in textual repr: transfer(address,uint256)
-	function transfer(address to, uint256 amount) external returns (bool);
-
-	/// @dev Transfer tokens from one address to another
-	/// @param from address The address which you want to send tokens from
-	/// @param to address The address which you want to transfer to
-	/// @param amount uint256 the amount of tokens to be transferred
-	/// @dev EVM selector for this function is: 0x23b872dd,
-	///  or in textual repr: transferFrom(address,address,uint256)
-	function transferFrom(
-		address from,
-		address to,
-		uint256 amount
-	) external returns (bool);
-
-	/// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`.
-	/// Beware that changing an allowance with this method brings the risk that someone may use both the old
-	/// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
-	/// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
-	/// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
-	/// @param spender The address which will spend the funds.
-	/// @param amount The amount of tokens to be spent.
-	/// @dev EVM selector for this function is: 0x095ea7b3,
-	///  or in textual repr: approve(address,uint256)
-	function approve(address spender, uint256 amount) external returns (bool);
-
-	/// @dev Function to check the amount of tokens that an owner allowed to a spender.
-	/// @param owner address The address which owns the funds.
-	/// @param spender address The address which will spend the funds.
-	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	/// @dev EVM selector for this function is: 0xdd62ed3e,
-	///  or in textual repr: allowance(address,address)
-	function allowance(address owner, address spender) external view returns (uint256);
-}
-
-interface UniqueRefungibleToken is Dummy, ERC165, ERC20, ERC20UniqueExtensions, ERC1633 {}
modifiedjs-packages/tests/eth/base.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/base.test.ts
+++ b/js-packages/tests/eth/base.test.ts
@@ -15,8 +15,8 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 
 
 describe('Contract calls', () => {
modifiedjs-packages/tests/eth/collectionAdmin.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/collectionAdmin.test.ts
+++ b/js-packages/tests/eth/collectionAdmin.test.ts
@@ -17,9 +17,9 @@
 import {expect} from 'chai';
 import {Pallets} from '@unique/test-utils/util.js';
 import type {IEthCrossAccountId} from '@unique-nft/playgrounds/types.js';
-import {usingEthPlaygrounds, itEth} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
+import {usingEthPlaygrounds, itEth} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise<any>) {
   const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress));
modifiedjs-packages/tests/eth/collectionHelperAddress.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/collectionHelperAddress.test.ts
+++ b/js-packages/tests/eth/collectionHelperAddress.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {COLLECTION_HELPER, Pallets} from '@unique/test-utils/util.js';
 
modifiedjs-packages/tests/eth/collectionLimits.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/collectionLimits.test.ts
+++ b/js-packages/tests/eth/collectionLimits.test.ts
@@ -1,7 +1,7 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField, CreateCollectionData} from './util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CollectionLimitField, CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 
 describe('Can set collection limits', () => {
modifiedjs-packages/tests/eth/collectionProperties.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/collectionProperties.test.ts
+++ b/js-packages/tests/eth/collectionProperties.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
 import {Pallets} from '@unique/test-utils/util.js';
 import type {IProperty, ITokenPropertyPermission} from '@unique-nft/playgrounds/types.js';
 import type {IKeyringPair} from '@polkadot/types/types';
modifiedjs-packages/tests/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/collectionSponsoring.test.ts
+++ b/js-packages/tests/eth/collectionSponsoring.test.ts
@@ -16,8 +16,8 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '@unique/test-utils/util.js';
-import {itEth, expect} from './util/index.js';
-import {CollectionLimitField, TokenPermissionField} from './util/playgrounds/types.js';
+import {itEth, expect} from '@unique/test-utils/eth/util.js';
+import {CollectionLimitField, TokenPermissionField} from '@unique/test-utils/eth/types.js';
 
 describe('evm nft collection sponsoring', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/contractSponsoring.test.ts
+++ b/js-packages/tests/eth/contractSponsoring.test.ts
@@ -15,10 +15,10 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
-import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from './util/index.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
+import {itEth, expect, SponsoringMode, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import {usingPlaygrounds} from '@unique/test-utils/util.js';
-import type {CompiledContract} from './util/playgrounds/types.js';
+import type {CompiledContract} from '@unique/test-utils/eth/types.js';
 
 describe('Sponsoring EVM contracts', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/createCollection.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createCollection.test.ts
+++ b/js-packages/tests/eth/createCollection.test.ts
@@ -17,8 +17,8 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {evmToAddress} from '@polkadot/util-crypto';
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, CollectionLimitField, CollectionMode, CreateCollectionData, TokenPermissionField, emptyAddress} from './util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, CollectionLimitField, CollectionMode, CreateCollectionData, TokenPermissionField, emptyAddress} from '@unique/test-utils/eth/types.js';
 import {CollectionFlag} from '@unique-nft/playgrounds/types.js';
 import type {IEthCrossAccountId, TCollectionMode} from '@unique-nft/playgrounds/types.js';
 
modifiedjs-packages/tests/eth/createFTCollection.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createFTCollection.seqtest.ts
+++ b/js-packages/tests/eth/createFTCollection.seqtest.ts
@@ -16,7 +16,7 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 
 const DECIMALS = 18;
 
modifiedjs-packages/tests/eth/createFTCollection.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createFTCollection.test.ts
+++ b/js-packages/tests/eth/createFTCollection.test.ts
@@ -17,8 +17,8 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {evmToAddress} from '@polkadot/util-crypto';
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CollectionLimitField} from '@unique/test-utils/eth/types.js';
 
 const DECIMALS = 18;
 
modifiedjs-packages/tests/eth/createNFTCollection.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createNFTCollection.seqtest.ts
+++ b/js-packages/tests/eth/createNFTCollection.seqtest.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 
 
 describe('Create NFT collection from EVM', () => {
modifiedjs-packages/tests/eth/createNFTCollection.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createNFTCollection.test.ts
+++ b/js-packages/tests/eth/createNFTCollection.test.ts
@@ -16,8 +16,8 @@
 
 import {evmToAddress} from '@polkadot/util-crypto';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CollectionLimitField} from '@unique/test-utils/eth/types.js';
 
 
 describe('Create NFT collection from EVM', () => {
modifiedjs-packages/tests/eth/createRFTCollection.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/createRFTCollection.test.ts
+++ b/js-packages/tests/eth/createRFTCollection.test.ts
@@ -17,8 +17,8 @@
 import {evmToAddress} from '@polkadot/util-crypto';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {CollectionLimitField} from './util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CollectionLimitField} from '@unique/test-utils/eth/types.js';
 
 
 describe('Create RFT collection from EVM', () => {
modifiedjs-packages/tests/eth/crossTransfer.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/crossTransfer.test.ts
+++ b/js-packages/tests/eth/crossTransfer.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {itEth, usingEthPlaygrounds} from './util/index.js';
+import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import {CrossAccountId} from '@unique-nft/playgrounds/unique.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 
modifiedjs-packages/tests/eth/destroyCollection.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/destroyCollection.test.ts
+++ b/js-packages/tests/eth/destroyCollection.test.ts
@@ -16,9 +16,9 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {TCollectionMode} from '@unique-nft/playgrounds/types.js';
-import {CreateCollectionData} from './util/playgrounds/types.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 describe('Destroy Collection from EVM', function() {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/ethFeesAreCorrect.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/ethFeesAreCorrect.test.ts
+++ b/js-packages/tests/eth/ethFeesAreCorrect.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://witww.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
 
 describe('Eth fees are correct', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/events.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/events.test.ts
+++ b/js-packages/tests/eth/events.test.ts
@@ -16,12 +16,12 @@
 
 import {expect} from 'chai';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import type {IEvent, TCollectionMode} from '@unique-nft/playgrounds/types.js';
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {CollectionLimitField, TokenPermissionField, CreateCollectionData} from './util/playgrounds/types.js';
-import type {NormalizedEvent} from './util/playgrounds/types.js';
+import {CollectionLimitField, TokenPermissionField, CreateCollectionData} from '@unique/test-utils/eth/types.js';
+import type {NormalizedEvent} from '@unique/test-utils/eth/types.js';
 
 let donor: IKeyringPair;
 
modifiedjs-packages/tests/eth/evmCoder.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/evmCoder.test.ts
+++ b/js-packages/tests/eth/evmCoder.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
+import {itEth, expect, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 
 const getContractSource = (collectionAddress: string, contractAddress: string): string => `
   // SPDX-License-Identifier: MIT
modifiedjs-packages/tests/eth/fractionalizer/fractionalizer.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/fractionalizer/fractionalizer.test.ts
+++ b/js-packages/tests/eth/fractionalizer/fractionalizer.test.ts
@@ -22,23 +22,25 @@
 
 import {Contract} from 'web3-eth-contract';
 
-import {usingEthPlaygrounds, expect, itEth} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
-import type {CompiledContract} from '../util/playgrounds/types.js';
+import {usingEthPlaygrounds, expect, itEth} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
+import type {CompiledContract} from '@unique/test-utils/eth/types.js';
 import {requirePalletsOrSkip, Pallets, makeNames} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
 
 let compiledFractionalizer: CompiledContract;
 
+const EVM_ABI_DIR = `${dirname}/../../../evm-abi`;
+
 const compileContract = async (helper: EthUniqueHelper): Promise<CompiledContract> => {
   if(!compiledFractionalizer) {
     compiledFractionalizer = await helper.ethContract.compile('Fractionalizer', (await readFile(`${dirname}/Fractionalizer.sol`)).toString(), [
-      {solPath: 'api/CollectionHelpers.sol', fsPath: `${dirname}/../api/CollectionHelpers.sol`},
-      {solPath: 'api/ContractHelpers.sol', fsPath: `${dirname}/../api/ContractHelpers.sol`},
-      {solPath: 'api/UniqueRefungibleToken.sol', fsPath: `${dirname}/../api/UniqueRefungibleToken.sol`},
-      {solPath: 'api/UniqueRefungible.sol', fsPath: `${dirname}/../api/UniqueRefungible.sol`},
-      {solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`},
+      {solPath: 'api/CollectionHelpers.sol', fsPath: `${EVM_ABI_DIR}/api/CollectionHelpers.sol`},
+      {solPath: 'api/ContractHelpers.sol', fsPath: `${EVM_ABI_DIR}/api/ContractHelpers.sol`},
+      {solPath: 'api/UniqueRefungibleToken.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueRefungibleToken.sol`},
+      {solPath: 'api/UniqueRefungible.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueRefungible.sol`},
+      {solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`},
     ]);
   }
   return compiledFractionalizer;
modifiedjs-packages/tests/eth/fungible.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/fungible.test.ts
+++ b/js-packages/tests/eth/fungible.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 
 describe('Fungible: Plain calls', () => {
modifiedjs-packages/tests/eth/getCode.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/getCode.test.ts
+++ b/js-packages/tests/eth/getCode.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {COLLECTION_HELPER, CONTRACT_HELPER} from '@unique/test-utils/util.js';
 
modifiedjs-packages/tests/eth/helpersSmoke.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/helpersSmoke.test.ts
+++ b/js-packages/tests/eth/helpersSmoke.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 
 describe('Helpers sanity check', () => {
modifiedjs-packages/tests/eth/marketplace-v2/marketplace.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/marketplace-v2/marketplace.test.ts
+++ b/js-packages/tests/eth/marketplace-v2/marketplace.test.ts
@@ -17,8 +17,8 @@
 import * as web3 from 'web3';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {readFile} from 'fs/promises';
-import {SponsoringMode, itEth, usingEthPlaygrounds} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {SponsoringMode, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {makeNames, expect} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
@@ -40,7 +40,7 @@
 
   async function deployMarket(helper: EthUniqueHelper, marketOwner: string) {
     const nodeModulesDir = `${dirname}/../../../node_modules`;
-    const solApiDir = `${dirname}/../api`;
+    const solApiDir = `${dirname}/../../../evm-abi/api`;
     return await helper.ethContract.deployByCode(
       marketOwner,
       'Market',
modifiedjs-packages/tests/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/marketplace/marketplace.test.ts
+++ b/js-packages/tests/eth/marketplace/marketplace.test.ts
@@ -16,10 +16,11 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {readFile} from 'fs/promises';
-import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '../util/index.js';
+import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from '@unique/test-utils/eth/util.js';
 import {makeNames} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
+const EVM_ABI_DIR = `${dirname}/../../../evm-abi`;
 
 describe('Matcher contract usage', () => {
   const PRICE = 2000n;
@@ -50,7 +51,7 @@
 
   itEth('With UNQ', async ({helper}) => {
     const matcherOwner = await helper.eth.createAccountWithBalance(donor);
-    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
 
     const sponsor = await helper.eth.createAccountWithBalance(donor);
     const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner);
@@ -102,7 +103,7 @@
 
   itEth('With escrow', async ({helper}) => {
     const matcherOwner = await helper.eth.createAccountWithBalance(donor);
-    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
 
     const sponsor = await helper.eth.createAccountWithBalance(donor);
     const escrow = await helper.eth.createAccountWithBalance(donor);
@@ -166,7 +167,7 @@
 
   itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => {
     const matcherOwner = await helper.eth.createAccountWithBalance(donor);
-    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
+    const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${EVM_ABI_DIR}/api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2);
 
     await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address);
 
modifiedjs-packages/tests/eth/migration.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/migration.seqtest.ts
+++ b/js-packages/tests/eth/migration.seqtest.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Struct} from '@polkadot/types';
 
modifiedjs-packages/tests/eth/nativeFungible.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/nativeFungible.test.ts
+++ b/js-packages/tests/eth/nativeFungible.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import {UniqueHelper} from '@unique-nft/playgrounds/unique.js';
 
 describe('NativeFungible: ERC20 calls', () => {
modifiedjs-packages/tests/eth/nativeRpc/estimateGas.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/nativeRpc/estimateGas.test.ts
+++ b/js-packages/tests/eth/nativeRpc/estimateGas.test.ts
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 
 
modifiedjs-packages/tests/eth/nesting/nest.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/nesting/nest.test.ts
+++ b/js-packages/tests/eth/nesting/nest.test.ts
@@ -1,8 +1,8 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
 
-import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 
 const createNestingCollection = async (
   helper: EthUniqueHelper,
modifiedjs-packages/tests/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/nonFungible.test.ts
+++ b/js-packages/tests/eth/nonFungible.test.ts
@@ -14,12 +14,12 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
 import type {ITokenPropertyPermission} from '@unique-nft/playgrounds/types.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from '@unique/test-utils/eth/types.js';
 
 describe('Check ERC721 token URI for NFT', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/payable.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/payable.test.ts
+++ b/js-packages/tests/eth/payable.test.ts
@@ -16,8 +16,8 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, expect, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {makeNames} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
@@ -261,11 +261,11 @@
       [
         {
           solPath: 'api/CollectionHelpers.sol',
-          fsPath: `${dirname}/api/CollectionHelpers.sol`,
+          fsPath: `${dirname}/../../evm-abi/api/CollectionHelpers.sol`,
         },
         {
           solPath: 'api/UniqueNFT.sol',
-          fsPath: `${dirname}/api/UniqueNFT.sol`,
+          fsPath: `${dirname}/../../evm-abi/api/UniqueNFT.sol`,
         },
       ],
     );
modifiedjs-packages/tests/eth/precompile.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/precompile.test.ts
+++ b/js-packages/tests/eth/precompile.test.ts
@@ -16,7 +16,7 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 
 describe('Precompiles', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/proxy/fungibleProxy.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/proxy/fungibleProxy.test.ts
+++ b/js-packages/tests/eth/proxy/fungibleProxy.test.ts
@@ -17,8 +17,8 @@
 import {expect} from 'chai';
 import {readFile} from 'fs/promises';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {makeNames} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
modifiedjs-packages/tests/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/proxy/nonFungibleProxy.test.ts
+++ b/js-packages/tests/eth/proxy/nonFungibleProxy.test.ts
@@ -16,8 +16,8 @@
 
 import {readFile} from 'fs/promises';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds, expect} from '../util/index.js';
-import {EthUniqueHelper} from '../util/playgrounds/unique.dev.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {makeNames} from '@unique/test-utils/util.js';
 
 const {dirname} = makeNames(import.meta.url);
modifiedjs-packages/tests/eth/proxyContract.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/proxyContract.test.ts
+++ b/js-packages/tests/eth/proxyContract.test.ts
@@ -16,8 +16,8 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 
-import {itEth, expect, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itEth, expect, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 
 describe('EVM payable contracts', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/reFungible.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/reFungible.test.ts
+++ b/js-packages/tests/eth/reFungible.test.ts
@@ -15,10 +15,10 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import type {ITokenPropertyPermission} from '@unique-nft/playgrounds/types.js';
-import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from './util/playgrounds/types.js';
+import {CREATE_COLLECTION_DATA_DEFAULTS, TokenPermissionField} from '@unique/test-utils/eth/types.js';
 
 describe('Refungible: Plain calls', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/reFungibleToken.test.ts
+++ b/js-packages/tests/eth/reFungibleToken.test.ts
@@ -15,8 +15,8 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
 
modifiedjs-packages/tests/eth/scheduling.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/scheduling.test.ts
+++ b/js-packages/tests/eth/scheduling.test.ts
@@ -15,8 +15,8 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {expect} from 'chai';
-import {itSchedEth} from './util/index.js';
-import {EthUniqueHelper} from './util/playgrounds/unique.dev.js';
+import {itSchedEth} from '@unique/test-utils/eth/util.js';
+import {EthUniqueHelper} from '@unique/test-utils/eth/index.js';
 import {Pallets, usingPlaygrounds} from '@unique/test-utils/util.js';
 
 describe('Scheduing EVM smart contracts', () => {
modifiedjs-packages/tests/eth/sponsoring.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/sponsoring.test.ts
+++ b/js-packages/tests/eth/sponsoring.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, expect, SponsoringMode} from './util/index.js';
+import {itEth, expect, SponsoringMode} from '@unique/test-utils/eth/util.js';
 import {usingPlaygrounds} from '@unique/test-utils/util.js';
 
 describe('EVM sponsoring', () => {
modifiedjs-packages/tests/eth/tokenProperties.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/tokenProperties.test.ts
+++ b/js-packages/tests/eth/tokenProperties.test.ts
@@ -16,11 +16,11 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
-import {itEth, usingEthPlaygrounds, expect} from './util/index.js';
+import {itEth, usingEthPlaygrounds, expect} from '@unique/test-utils/eth/util.js';
 import type {ITokenPropertyPermission} from '@unique-nft/playgrounds/types.js';
 import {Pallets} from '@unique/test-utils/util.js';
 import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '@unique-nft/playgrounds/unique.js';
-import {CreateCollectionData, TokenPermissionField} from './util/playgrounds/types.js';
+import {CreateCollectionData, TokenPermissionField} from '@unique/test-utils/eth/types.js';
 
 describe('EVM token properties', () => {
   let donor: IKeyringPair;
modifiedjs-packages/tests/eth/tokens/callMethodsERC20.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/tokens/callMethodsERC20.test.ts
+++ b/js-packages/tests/eth/tokens/callMethodsERC20.test.ts
@@ -15,9 +15,9 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 [
   {mode: 'ft' as const, requiredPallets: []},
modifiedjs-packages/tests/eth/tokens/callMethodsERC721.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/tokens/callMethodsERC721.test.ts
+++ b/js-packages/tests/eth/tokens/callMethodsERC721.test.ts
@@ -15,9 +15,9 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {Pallets} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import type {IKeyringPair} from '@polkadot/types/types';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 
 describe('ERC-721 call methods', () => {
modifiedjs-packages/tests/eth/tokens/minting.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/tokens/minting.test.ts
+++ b/js-packages/tests/eth/tokens/minting.test.ts
@@ -16,8 +16,8 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {Pallets} from '@unique/test-utils/util.js';
-import {expect, itEth, usingEthPlaygrounds} from '../util/index.js';
-import {CreateCollectionData} from '../util/playgrounds/types.js';
+import {expect, itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
+import {CreateCollectionData} from '@unique/test-utils/eth/types.js';
 
 
 describe('Minting tokens', () => {
modifiedjs-packages/tests/eth/transferValue.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/transferValue.test.ts
+++ b/js-packages/tests/eth/transferValue.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import type {IKeyringPair} from '@polkadot/types/types';
-import {itEth, usingEthPlaygrounds} from './util/index.js';
+import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import {expect} from 'chai';
 
 describe('Send value to contract', () => {
deletedjs-packages/tests/eth/util/index.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/util/index.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-import * as path from 'path';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import config from '../../config.js';
-
-import {EthUniqueHelper} from './playgrounds/unique.dev.js';
-import {SilentLogger, SilentConsole} from '@unique/test-utils';
-import type {SchedKind} from '@unique/test-utils/util.js';
-
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import chaiLike from 'chai-like';
-import {getTestSeed, MINIMUM_DONOR_FUND, requirePalletsOrSkip, makeNames} from '@unique/test-utils/util.js';
-
-chai.use(chaiAsPromised);
-chai.use(chaiLike);
-export const expect = chai.expect;
-
-export enum SponsoringMode {
-  Disabled = 0,
-  Allowlisted = 1,
-  Generous = 2,
-}
-
-type PrivateKeyFn = (seed: string | {filename?: string, url?: string}) => Promise<IKeyringPair>;
-
-export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privateKey: PrivateKeyFn) => Promise<void>) => {
-  const silentConsole = new SilentConsole();
-  silentConsole.enable();
-
-  const helper = new EthUniqueHelper(new SilentLogger());
-
-  try {
-    await helper.connect(config.substrateUrl);
-    await helper.connectWeb3(config.substrateUrl);
-    const ss58Format = helper.chain.getChainProperties().ss58Format;
-    const privateKey: PrivateKeyFn = async (seed) => {
-      if(typeof seed === 'string') {
-        return helper.util.fromSeed(seed, ss58Format);
-      }
-      if(seed.url) {
-        const {filename} = makeNames(seed.url);
-        seed.filename = filename;
-      } else if(seed.filename) {
-        // Pass
-      } else {
-        throw new Error('no url nor filename set');
-      }
-      const actualSeed = getTestSeed(seed.filename);
-      let account = helper.util.fromSeed(actualSeed, ss58Format);
-      if(await helper.balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND) {
-        console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`);
-        account = helper.util.fromSeed('//Alice', ss58Format);
-      }
-      return account;
-    };
-    await code(helper, privateKey);
-  }
-  finally {
-    await helper.disconnect();
-    silentConsole.disable();
-  }
-};
-
-export function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
-  (opts.only ? it.only :
-    opts.skip ? it.skip : it)(name, async function() {
-    await usingEthPlaygrounds(async (helper, privateKey) => {
-      if(opts.requiredPallets) {
-        requirePalletsOrSkip(this, helper, opts.requiredPallets);
-      }
-
-      await cb({helper, privateKey});
-    });
-  });
-}
-
-export function itEthIfWithPallet(name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
-  return itEth(name, cb, {requiredPallets: required, ...opts});
-}
-
-itEth.only = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEth(name, cb, {only: true});
-itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itEth(name, cb, {skip: true});
-
-itEthIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {only: true});
-itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any) => itEthIfWithPallet(name, required, cb, {skip: true});
-itEth.ifWithPallets = itEthIfWithPallet;
-
-export function itSchedEth(
-  name: string,
-  cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any,
-  opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {},
-) {
-  itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts);
-  itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts);
-}
-itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {only: true});
-itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise<IKeyringPair> }) => any) => itSchedEth(name, cb, {skip: true});
-itSchedEth.ifWithPallets = itSchedIfWithPallets;
-
-function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: PrivateKeyFn }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) {
-  return itSchedEth(name, cb, {requiredPallets: required, ...opts});
-}
deletedjs-packages/tests/eth/util/playgrounds/types.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/util/playgrounds/types.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import {CollectionFlag} from '@unique-nft/playgrounds/types.js';
-import type {TCollectionMode} from '@unique-nft/playgrounds/types.js';
-
-export interface ContractImports {
-  solPath: string;
-  fsPath: string;
-}
-
-export interface CompiledContract {
-  abi: any;
-  object: string;
-}
-
-export type NormalizedEvent = {
-  address: string,
-  event: string,
-  args: { [key: string]: string }
-};
-
-export interface OptionUint {
-  status: boolean,
-  value: bigint,
-}
-
-export type EthAddress = string;
-
-export interface CrossAddress {
-  readonly eth: EthAddress,
-  readonly sub: string | Uint8Array,
-}
-
-export type EthProperty = string[];
-
-export enum TokenPermissionField {
-  Mutable,
-  TokenOwner,
-  CollectionAdmin
-}
-
-export enum CollectionLimitField {
-  AccountTokenOwnership,
-	SponsoredDataSize,
-	SponsoredDataRateLimit,
-	TokenLimit,
-	SponsorTransferTimeout,
-	SponsorApproveTimeout,
-	OwnerCanTransfer,
-	OwnerCanDestroy,
-	TransferEnabled
-}
-
-export interface CollectionLimit {
-  field: CollectionLimitField,
-  value: OptionUint,
-}
-
-export interface CollectionLimitValue {
-  field: CollectionLimitField,
-  value: bigint,
-}
-
-export enum CollectionMode {
-	Nonfungible,
-	Fungible,
-	Refungible,
-}
-
-export interface PropertyPermission {
-  code: TokenPermissionField,
-  value: boolean,
-}
-export interface TokenPropertyPermission {
-  key: string,
-  permissions: PropertyPermission[],
-}
-export interface CollectionNestingAndPermission {
-  token_owner: boolean,
-  collection_admin: boolean,
-  restricted: string[],
-}
-
-export const emptyAddress: [string, string] = [
-  '0x0000000000000000000000000000000000000000',
-  '0',
-];
-
-export const CREATE_COLLECTION_DATA_DEFAULTS = {
-  decimals: 0,
-  properties: [],
-  tokenPropertyPermissions: [],
-  adminList: [],
-  nestingSettings: {token_owner: false, collection_admin: false, restricted: []},
-  limits: [],
-  pendingSponsor: emptyAddress,
-  flags: 0,
-};
-
-export interface Property {
-  key: string;
-  value: Buffer;
-}
-
-export class CreateCollectionData {
-  name: string;
-  description: string;
-  tokenPrefix: string;
-  collectionMode: TCollectionMode;
-  decimals? = 0;
-  properties?: Property[] = [];
-  tokenPropertyPermissions?: TokenPropertyPermission[] = [];
-  adminList?: CrossAddress[] = [];
-  nestingSettings?: CollectionNestingAndPermission = {token_owner: false, collection_admin: false, restricted: []};
-  limits?: CollectionLimitValue[] = [];
-  pendingSponsor?: [string, string] = emptyAddress;
-  flags?: number | CollectionFlag[] = [0];
-
-  constructor(
-    name: string,
-    description: string,
-    tokenPrefix: string,
-    collectionMode: TCollectionMode,
-    decimals = 18,
-  ) {
-    this.name = name;
-    this.description = description;
-    this.tokenPrefix = tokenPrefix;
-    this.collectionMode = collectionMode;
-    if(collectionMode == 'ft')
-      this.decimals = decimals;
-    else
-      this.decimals = 0;
-  }
-}
deletedjs-packages/tests/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/util/playgrounds/unique.dev.ts
+++ /dev/null
@@ -1,616 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// SPDX-License-Identifier: Apache-2.0
-
-/* eslint-disable function-call-argument-newline */
-
-import {readFile} from 'fs/promises';
-
-import * as web3 from 'web3';
-import {WebsocketProvider} from 'web3-core';
-import {Contract} from 'web3-eth-contract';
-
-// @ts-ignore
-import solc from 'solc';
-
-import {evmToAddress} from '@polkadot/util-crypto';
-import type {IKeyringPair} from '@polkadot/types/types';
-
-import {ArrangeGroup, DevUniqueHelper} from '@unique/test-utils/index.js';
-
-import type {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types.js';
-import {CollectionMode, CreateCollectionData} from './types.js';
-
-// Native contracts ABI
-import collectionHelpersAbi from '../../abi/collectionHelpers.json' assert {type: 'json'};
-import nativeFungibleAbi from '../../abi/nativeFungible.json' assert {type: 'json'};
-import fungibleAbi from '../../abi/fungible.json' assert {type: 'json'};
-import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json' assert {type: 'json'};
-import nonFungibleAbi from '../../abi/nonFungible.json' assert {type: 'json'};
-import nonFungibleDeprecatedAbi from '../../abi/nonFungibleDeprecated.json' assert {type: 'json'};
-import refungibleAbi from '../../abi/reFungible.json' assert {type: 'json'};
-import refungibleDeprecatedAbi from '../../abi/reFungibleDeprecated.json' assert {type: 'json'};
-import refungibleTokenAbi from '../../abi/reFungibleToken.json' assert {type: 'json'};
-import refungibleTokenDeprecatedAbi from '../../abi/reFungibleTokenDeprecated.json' assert {type: 'json'};
-import contractHelpersAbi from '../../abi/contractHelpers.json' assert {type: 'json'};
-import type {ICrossAccountId, TEthereumAccount, TCollectionMode} from '@unique-nft/playgrounds/types.js';
-
-class EthGroupBase {
-  helper: EthUniqueHelper;
-  gasPrice?: string;
-
-  constructor(helper: EthUniqueHelper) {
-    this.helper = helper;
-  }
-  async getGasPrice() {
-    if(this.gasPrice)
-      return this.gasPrice;
-    this.gasPrice = await this.helper.getWeb3().eth.getGasPrice();
-    return this.gasPrice;
-  }
-}
-
-class ContractGroup extends EthGroupBase {
-  async findImports(imports?: ContractImports[]) {
-    if(!imports) return function(path: string) {
-      return {error: `File not found: ${path}`};
-    };
-
-    const knownImports = {} as { [key: string]: string };
-    for(const imp of imports) {
-      knownImports[imp.solPath] = (await readFile(imp.fsPath)).toString();
-    }
-
-    return function(path: string) {
-      if(path in knownImports) return {contents: knownImports[path]};
-      return {error: `File not found: ${path}`};
-    };
-  }
-
-  async compile(name: string, src: string, imports?: ContractImports[]): Promise<CompiledContract> {
-    const compiled = JSON.parse(solc.compile(JSON.stringify({
-      language: 'Solidity',
-      sources: {
-        [`${name}.sol`]: {
-          content: src,
-        },
-      },
-      settings: {
-        outputSelection: {
-          '*': {
-            '*': ['*'],
-          },
-        },
-      },
-    }), {import: await this.findImports(imports)}));
-
-    const hasErrors = compiled['errors']
-      && compiled['errors'].length > 0
-      && compiled.errors.some(function(err: any) {
-        return err.severity == 'error';
-      });
-
-    if(hasErrors) {
-      throw compiled.errors;
-    }
-    const out = compiled.contracts[`${name}.sol`][name];
-
-    return {
-      abi: out.abi,
-      object: '0x' + out.evm.bytecode.object,
-    };
-  }
-
-  async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number, args?: any[]): Promise<Contract> {
-    const compiledContract = await this.compile(name, src, imports);
-    return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas, args);
-  }
-
-  async deployByAbi(signer: string, abi: any, object: string, gas?: number, args?: any[]): Promise<Contract> {
-    const web3 = this.helper.getWeb3();
-    const contract = new web3.eth.Contract(abi, undefined, {
-      data: object,
-      from: signer,
-      gas: gas ?? this.helper.eth.DEFAULT_GAS,
-    });
-    return await contract.deploy({data: object, arguments: args}).send({from: signer});
-  }
-
-}
-
-class NativeContractGroup extends EthGroupBase {
-
-  contractHelpers(caller: string) {
-    const web3 = this.helper.getWeb3();
-    return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {
-      from: caller,
-      gas: this.helper.eth.DEFAULT_GAS,
-    });
-  }
-
-  collectionHelpers(caller: string) {
-    const web3 = this.helper.getWeb3();
-    return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {
-      from: caller,
-      gas: this.helper.eth.DEFAULT_GAS,
-    });
-  }
-
-  collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) {
-    let abi;
-    if(address === this.helper.ethAddress.fromCollectionId(0)) {
-      abi = nativeFungibleAbi;
-    } else {
-      abi ={
-        'nft': nonFungibleAbi,
-        'rft': refungibleAbi,
-        'ft': fungibleAbi,
-      }[mode];
-    }
-    if(mergeDeprecated) {
-      const deprecated = {
-        'nft': nonFungibleDeprecatedAbi,
-        'rft': refungibleDeprecatedAbi,
-        'ft': fungibleDeprecatedAbi,
-      }[mode];
-      abi = [...abi, ...deprecated];
-    }
-    const web3 = this.helper.getWeb3();
-    return new web3.eth.Contract(abi as any, address, {
-      gas: this.helper.eth.DEFAULT_GAS,
-      ...(caller ? {from: caller} : {}),
-    });
-  }
-
-  collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string, mergeDeprecated = false) {
-    return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated);
-  }
-
-  rftToken(address: string, caller?: string, mergeDeprecated = false) {
-    const web3 = this.helper.getWeb3();
-    const abi = mergeDeprecated ? [...refungibleTokenAbi, ...refungibleTokenDeprecatedAbi] : refungibleTokenAbi;
-    return new web3.eth.Contract(abi as any, address, {
-      gas: this.helper.eth.DEFAULT_GAS,
-      ...(caller ? {from: caller} : {}),
-    });
-  }
-
-  rftTokenById(collectionId: number, tokenId: number, caller?: string, mergeDeprecated = false) {
-    return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller, mergeDeprecated);
-  }
-}
-
-class CreateCollectionTransaction {
-  signer: string;
-  data: CreateCollectionData;
-  mergeDeprecated: boolean;
-  helper: EthUniqueHelper;
-
-  constructor(helper: EthUniqueHelper, signer: string, data: CreateCollectionData, mergeDeprecated = false) {
-    this.helper = helper;
-    this.signer = signer;
-
-    let flags = 0;
-    // convert CollectionFlags to number and join them in one number
-    if(!data.flags) {
-      flags = 0;
-    } else if(typeof data.flags == 'number') {
-      flags = data.flags;
-    } else {
-      for(let i = 0; i < data.flags.length; i++){
-        const flag = data.flags[i];
-        flags = flags | flag;
-      }
-    }
-    data.flags = flags;
-
-    this.data = data;
-    this.mergeDeprecated = mergeDeprecated;
-  }
-
-  // eslint-disable-next-line require-await
-  private async createTransaction() {
-    const collectionHelper = this.helper.ethNativeContract.collectionHelpers(this.signer);
-    let collectionMode;
-    switch (this.data.collectionMode) {
-      case 'nft': collectionMode = CollectionMode.Nonfungible; break;
-      case 'rft': collectionMode = CollectionMode.Refungible; break;
-      case 'ft': collectionMode = CollectionMode.Fungible; break;
-    }
-
-    const tx = collectionHelper.methods.createCollection([
-      this.data.name,
-      this.data.description,
-      this.data.tokenPrefix,
-      collectionMode,
-      this.data.decimals,
-      this.data.properties,
-      this.data.tokenPropertyPermissions,
-      this.data.adminList,
-      this.data.nestingSettings,
-      this.data.limits,
-      this.data.pendingSponsor,
-      this.data.flags,
-    ]);
-    return tx;
-  }
-
-  async send(options?: any): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[], collection: Contract }> {
-    const collectionCreationPrice = {
-      value: Number(this.helper.balance.getCollectionCreationPrice()),
-    };
-    const tx = await this.createTransaction();
-    const result = await tx.send({...options, ...collectionCreationPrice});
-
-    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
-    const events = this.helper.eth.normalizeEvents(result.events);
-    const collection = await this.helper.ethNativeContract.collectionById(collectionId, this.data.collectionMode, this.signer, this.mergeDeprecated);
-
-    return {collectionId, collectionAddress, events, collection};
-  }
-
-  async call(options?: any) {
-    const collectionCreationPrice = {
-      value: Number(this.helper.balance.getCollectionCreationPrice()),
-    };
-    const tx = await this.createTransaction();
-
-    return await tx.call({...options, ...collectionCreationPrice});
-  }
-}
-
-
-class EthGroup extends EthGroupBase {
-  DEFAULT_GAS = 2_500_000;
-
-  createAccount() {
-    const web3 = this.helper.getWeb3();
-    const account = web3.eth.accounts.create();
-    web3.eth.accounts.wallet.add(account.privateKey);
-    return account.address;
-  }
-
-  async createAccountWithBalance(donor: IKeyringPair, amount = 600n) {
-    const account = this.createAccount();
-    await this.transferBalanceFromSubstrate(donor, account, amount);
-
-    return account;
-  }
-
-  async transferBalanceFromSubstrate(donor: IKeyringPair, recepient: string, amount = 100n, inTokens = true) {
-    return await this.helper.balance.transferToSubstrate(donor, evmToAddress(recepient), amount * (inTokens ? this.helper.balance.getOneTokenNominal() : 1n));
-  }
-
-  async getCollectionCreationFee(signer: string) {
-    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-    return await collectionHelper.methods.collectionCreationFee().call();
-  }
-
-  async sendEVM(signer: IKeyringPair, contractAddress: string, abi: string, value: string, gasLimit?: number) {
-    if(!gasLimit) gasLimit = this.DEFAULT_GAS;
-    const web3 = this.helper.getWeb3();
-    // FIXME: can't send legacy transaction using tx.evm.call
-    const gasPrice = await web3.eth.getGasPrice();
-    // TODO: check execution status
-    await this.helper.executeExtrinsic(
-      signer,
-      'api.tx.evm.call', [this.helper.address.substrateToEth(signer.address), contractAddress, abi, value, gasLimit, gasPrice, null, null, []],
-      true,
-    );
-  }
-
-  async callEVM(signer: TEthereumAccount, contractAddress: string, abi: string) {
-    return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
-  }
-
-  createCollectionMethodName(mode: TCollectionMode) {
-    switch (mode) {
-      case 'ft':
-        return 'createFTCollection';
-      case 'nft':
-        return 'createNFTCollection';
-      case 'rft':
-        return 'createRFTCollection';
-    }
-  }
-
-  createCollection(signer: string, data: CreateCollectionData, mergeDeprecated = false): CreateCollectionTransaction {
-    return new CreateCollectionTransaction(this.helper, signer, data, mergeDeprecated);
-  }
-
-  createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
-  }
-
-  async createERC721MetadataCompatibleCollection(signer: string, data: CreateCollectionData, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
-    const {collectionId, collectionAddress, events} = await this.createCollection(signer, data).send();
-
-    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
-    return {collectionId, collectionAddress, events};
-  }
-
-  async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
-    const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'nft')).send();
-
-    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
-    return {collectionId, collectionAddress, events};
-  }
-
-  createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
-  }
-
-  createFungibleCollection(signer: string, name: string, _decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    return this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'ft')).send();
-  }
-
-  async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
-    const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer);
-
-    const {collectionId, collectionAddress, events} = await this.createCollection(signer, new CreateCollectionData(name, description, tokenPrefix, 'rft')).send();
-
-    await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send();
-
-    return {collectionId, collectionAddress, events};
-  }
-
-  async deployCollectorContract(signer: string): Promise<Contract> {
-    return await this.helper.ethContract.deployByCode(signer, 'Collector', `
-    // SPDX-License-Identifier: UNLICENSED
-    pragma solidity ^0.8.6;
-
-    contract Collector {
-      uint256 collected;
-      fallback() external payable {
-        giveMoney();
-      }
-      function giveMoney() public payable {
-        collected += msg.value;
-      }
-      function getCollected() public view returns (uint256) {
-        return collected;
-      }
-      function getUnaccounted() public view returns (uint256) {
-        return address(this).balance - collected;
-      }
-
-      function withdraw(address payable target) public {
-        target.transfer(collected);
-        collected = 0;
-      }
-    }
-  `);
-  }
-
-  async deployFlipper(signer: string): Promise<Contract> {
-    return await this.helper.ethContract.deployByCode(signer, 'Flipper', `
-    // SPDX-License-Identifier: UNLICENSED
-    pragma solidity ^0.8.6;
-
-    contract Flipper {
-      bool value = false;
-      function flip() public {
-        value = !value;
-      }
-      function getValue() public view returns (bool) {
-        return value;
-      }
-    }
-  `);
-  }
-
-  async recordCallFee(user: string, call: () => Promise<any>): Promise<bigint> {
-    const before = await this.helper.balance.getEthereum(user);
-    await call();
-    // In dev mode, the transaction might not finish processing in time
-    await this.helper.wait.newBlocks(1);
-    const after = await this.helper.balance.getEthereum(user);
-
-    return before - after;
-  }
-
-  normalizeEvents(events: any): NormalizedEvent[] {
-    const output = [];
-    for(const key of Object.keys(events)) {
-      if(key.match(/^[0-9]+$/)) {
-        output.push(events[key]);
-      } else if(Array.isArray(events[key])) {
-        output.push(...events[key]);
-      } else {
-        output.push(events[key]);
-      }
-    }
-    output.sort((a, b) => a.logIndex - b.logIndex);
-    return output.map(({address, event, returnValues}) => {
-      const args: { [key: string]: string } = {};
-      for(const key of Object.keys(returnValues)) {
-        if(!key.match(/^[0-9]+$/)) {
-          args[key] = returnValues[key];
-        }
-      }
-      return {
-        address,
-        event,
-        args,
-      };
-    });
-  }
-
-  async calculateFee(address: ICrossAccountId, code: () => Promise<any>): Promise<bigint> {
-    const wrappedCode = async () => {
-      await code();
-      // In dev mode, the transaction might not finish processing in time
-      await this.helper.wait.newBlocks(1);
-    };
-    return await this.helper.arrange.calculcateFee(address, wrappedCode);
-  }
-}
-
-class EthAddressGroup extends EthGroupBase {
-  extractCollectionId(address: string): number {
-    if(!(address.length === 42 || address.length === 40)) throw new Error('address wrong format');
-    return parseInt(address.slice(address.length - 8), 16);
-  }
-
-  fromCollectionId(collectionId: number): string {
-    if(collectionId >= 0xffffffff || collectionId < 0) throw new Error('collectionId overflow');
-    return web3.default.utils.toChecksumAddress(`0x17c4e6453cc49aaaaeaca894e6d9683e${collectionId.toString(16).padStart(8, '0')}`);
-  }
-
-  extractTokenId(address: string): { collectionId: number, tokenId: number } {
-    if(!address.startsWith('0x'))
-      throw 'address not starts with "0x"';
-    if(address.length > 42)
-      throw 'address length is more than 20 bytes';
-    return {
-      collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
-      tokenId: Number('0x' + address.substring(address.length - 8)),
-    };
-  }
-
-  fromTokenId(collectionId: number, tokenId: number): string {
-    return this.helper.util.getTokenAddress({collectionId, tokenId});
-  }
-
-  normalizeAddress(address: string): string {
-    return '0x' + address.substring(address.length - 40);
-  }
-}
-export class EthPropertyGroup extends EthGroupBase {
-  property(key: string, value: string): EthProperty {
-    return [
-      key,
-      '0x' + Buffer.from(value).toString('hex'),
-    ];
-  }
-}
-export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper;
-
-export class EthCrossAccountGroup extends EthGroupBase {
-  createAccount(): CrossAddress {
-    return this.fromAddress(this.helper.eth.createAccount());
-  }
-
-  async createAccountWithBalance(donor: IKeyringPair, amount = 100n) {
-    return this.fromAddress(await this.helper.eth.createAccountWithBalance(donor, amount));
-  }
-
-  fromAddress(address: TEthereumAccount): CrossAddress {
-    return {
-      eth: address,
-      sub: '0',
-    };
-  }
-
-  fromAddr(address: TEthereumAccount): [string, string] {
-    return [
-      address,
-      '0',
-    ];
-  }
-
-  fromKeyringPair(keyring: IKeyringPair): CrossAddress {
-    return {
-      eth: '0x0000000000000000000000000000000000000000',
-      sub: keyring.addressRaw,
-    };
-  }
-}
-
-export class FeeGas {
-  fee: number | bigint = 0n;
-
-  gas: number | bigint = 0n;
-
-  public static async build(helper: EthUniqueHelper, fee: bigint): Promise<FeeGas> {
-    const instance = new FeeGas();
-    instance.fee = instance.convertToTokens(fee);
-    instance.gas = await instance.convertToGas(fee, helper);
-    return instance;
-  }
-
-  private async convertToGas(fee: bigint, helper: EthUniqueHelper): Promise<bigint> {
-    const gasPrice = BigInt(await helper.getWeb3().eth.getGasPrice());
-    return fee / gasPrice;
-  }
-
-  private convertToTokens(value: bigint, nominal = 1_000_000_000_000_000_000n): number {
-    return Number((value * 1000n) / nominal) / 1000;
-  }
-}
-
-class EthArrangeGroup extends ArrangeGroup {
-  declare helper: EthUniqueHelper;
-
-  constructor(helper: EthUniqueHelper) {
-    super(helper);
-    this.helper = helper;
-  }
-
-  async calculcateFeeGas(payer: ICrossAccountId, promise: () => Promise<any>): Promise<FeeGas> {
-    const fee = await this.calculcateFee(payer, promise);
-    return await FeeGas.build(this.helper, fee);
-  }
-}
-export class EthUniqueHelper extends DevUniqueHelper {
-  web3: web3.default | null = null;
-  web3Provider: WebsocketProvider | null = null;
-
-  eth: EthGroup;
-  ethAddress: EthAddressGroup;
-  ethCrossAccount: EthCrossAccountGroup;
-  ethNativeContract: NativeContractGroup;
-  ethContract: ContractGroup;
-  ethProperty: EthPropertyGroup;
-  declare arrange: EthArrangeGroup;
-  constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: { [key: string]: any } = {}) {
-    options.helperBase = options.helperBase ?? EthUniqueHelper;
-
-    super(logger, options);
-    this.eth = new EthGroup(this);
-    this.ethAddress = new EthAddressGroup(this);
-    this.ethCrossAccount = new EthCrossAccountGroup(this);
-    this.ethNativeContract = new NativeContractGroup(this);
-    this.ethContract = new ContractGroup(this);
-    this.ethProperty = new EthPropertyGroup(this);
-    this.arrange = new EthArrangeGroup(this);
-    super.arrange = this.arrange;
-  }
-
-  getWeb3(): web3.default {
-    if(this.web3 === null) throw Error('Web3 not connected');
-    return this.web3;
-  }
-
-  connectWeb3(wsEndpoint: string) {
-    if(this.web3 !== null) return;
-    this.web3Provider = new web3.default.providers.WebsocketProvider(wsEndpoint);
-    this.web3 = new web3.default(this.web3Provider);
-  }
-
-  override async disconnect() {
-    if(this.web3 === null) return;
-    this.web3Provider?.connection.close();
-
-    await super.disconnect();
-  }
-
-  override clearApi() {
-    super.clearApi();
-    this.web3 = null;
-  }
-
-  override clone(helperCls: EthUniqueHelperConstructor, options?: { [key: string]: any; }): EthUniqueHelper {
-    const newHelper = super.clone(helperCls, options) as EthUniqueHelper;
-    newHelper.web3 = this.web3;
-    newHelper.web3Provider = this.web3Provider;
-
-    return newHelper;
-  }
-}
modifiedjs-packages/tests/maintenance.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/maintenance.seqtest.ts
+++ b/js-packages/tests/maintenance.seqtest.ts
@@ -17,8 +17,8 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {ApiPromise} from '@polkadot/api';
 import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from '@unique/test-utils/util.js';
-import {itEth} from './eth/util/index.js';
-import {main as correctState} from './migrations/correctStateAfterMaintenance.js';
+import {itEth} from '@unique/test-utils/eth/util.js';
+import {main as correctState} from '@unique/scripts/correctStateAfterMaintenance.js';
 import type {PalletBalancesIdAmount} from '@polkadot/types/lookup';
 import type {Vec} from '@polkadot/types-codec';
 
deletedjs-packages/tests/migrations/942057-appPromotion/README.mddiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Update Procedure
-
-- Enable maintenance mode
-- [Collect migration data using ChainQL](#stakers-data-loading)
-- ❗️❗️❗️ Initiate the runtime upgrade only at this point ❗️❗️❗️
-- Wait for the upgrade to complete
-- [Execute offchain migration](#execute-offchain-migration)
-- Disable maintenance mode
-
-## Stakers Data Loading
-
-Set the environment variable (WS_RPC). For example, ws://localhost:9944. Execute the following command:
-
-```sh
-chainql --tla-str=chainUrl=<WS_RPC> stakersParser.jsonnet > output.json
-```
-
-where `<WS_RPC>` - is the network address.
-
-Example for Opal:
-
-```sh
-chainql --tla-str=chainUrl=wss://eu-ws-opal.unique.network:443 stakersParser.jsonnet > output.json
-```
-
-To install chainql, execute the following command:
-
-```sh
-cargo install chainql
-```
-
-## Execute offchain migration
-
-To run, you need to set an environment variables:
-- `SUPERUSER_SEED` – the sudo key seed.
-- `WS_RPC` – the network address
-
-Run the migration by executing the following command:
-
-```sh
-npx ts-node --esm executeMigration.ts
-```
deletedjs-packages/tests/migrations/942057-appPromotion/collectData.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/collectData.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {exec} from 'child_process';
-import path from 'path';
-import {dirname} from 'path';
-import {fileURLToPath} from 'url';
-
-export const collectData = () => {
-  const dirName = dirname(fileURLToPath(import.meta.url));
-
-  const pathToScript = path.resolve(dirName, './stakersParser.jsonnet');
-  const outputPath = path.resolve(dirName, './output.json');
-  exec(`chainql --tla-str=chainUrl=ws://127.0.0.1:9944 ${pathToScript} > ${outputPath}`);
-};
deletedjs-packages/tests/migrations/942057-appPromotion/executeMigration.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/executeMigration.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import {migrateLockedToFreeze} from './lockedToFreeze.js';
-
-
-const WS_RPC = process.env.WS_RPC || 'wss://ws-opal.unique.network:443';
-const SUPERUSER_SEED = process.env.SUPERUSER_SEED || '';
-
-migrateLockedToFreeze({
-  wsEndpoint: WS_RPC,
-  donorSeed: SUPERUSER_SEED,
-})
-  .catch(console.error);
\ No newline at end of file
deletedjs-packages/tests/migrations/942057-appPromotion/index.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import type {Migration} from '../index.js';
-import {collectData} from './collectData.js';
-import {migrateLockedToFreeze} from './lockedToFreeze.js';
-
-export const migration: Migration = {
-  async before() {
-    await collectData();
-  },
-  async after() {
-    await migrateLockedToFreeze();
-  },
-};
\ No newline at end of file
deletedjs-packages/tests/migrations/942057-appPromotion/lockedToFreeze.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/lockedToFreeze.ts
+++ /dev/null
@@ -1,259 +0,0 @@
-// import { usingApi, privateKey, onlySign } from "./../../load/lib";
-import * as fs from 'fs';
-import {usingPlaygrounds} from '@unique/test-utils/util.js';
-import path, {dirname} from 'path';
-import {isInteger, parse} from 'lossless-json';
-import {fileURLToPath} from 'url';
-import config from '../../config.js';
-
-
-const WS_ENDPOINT = config.substrateUrl;
-const DONOR_SEED = '//Alice';
-const UPDATE_IF_VERSION = 942057;
-
-export function customNumberParser(value: any) {
-  return isInteger(value) ? BigInt(value) : parseFloat(value);
-}
-
-export const migrateLockedToFreeze = async(options: { wsEndpoint: string; donorSeed: string } = {
-  wsEndpoint: WS_ENDPOINT,
-  donorSeed: DONOR_SEED,
-}) => {
-  await usingPlaygrounds(async (helper, privateKey) => {
-    const api = helper.getApi();
-    // 1. Check version equal 942057 or skip
-    console.log((api.consts.system.version as any).specVersion.toNumber());
-    if((api.consts.system.version as any).specVersion.toNumber() != UPDATE_IF_VERSION) {
-      console.log("Version isn't 942057.");
-      return;
-    }
-
-    // 2. Get sudo signer
-    const signer = await privateKey(options.donorSeed);
-    console.log('2. Getting sudo:', signer.address);
-
-    // 3. Parse data to migrate
-    console.log('3. Parsing chainql results...');
-    const dirName = dirname(fileURLToPath(import.meta.url));
-    const parsingResult = parse(fs.readFileSync(path.resolve(dirName, 'output.json'), 'utf-8'), undefined, customNumberParser);
-
-    const chainqlImportData = parsingResult as {
-      address: string;
-      balance: string;
-      account: {
-        fee_frozen: string,
-        free: string,
-        misc_frozen: string,
-        reserved: string,
-      },
-      locks: {
-        amount: string,
-        id: string,
-      }[],
-      stakes: object,
-      unstakes: object,
-    }[];
-    testChainqlData(chainqlImportData);
-
-    const stakers = chainqlImportData.map((i) => i.address);
-
-    // 3.1 Split into chunks by 100
-    console.log('3.1 Splitting into chunks...');
-    const stakersChunks = chunk(stakers, 100);
-    console.log('3.1 Done, total chunks:', stakersChunks.length);
-
-    // 4. Get signer/sudo nonce
-    console.log('4. Getting sudo nonce...');
-    const signerAccount = (
-        await api.query.system.account(signer.address)
-      ).toJSON() as any;
-
-    let nonce: number = signerAccount.nonce;
-    console.log('4. Sudo nonce is:', nonce);
-
-    // 5. Only sign upgradeAccounts-transactions for each chunk
-    console.log('5. Signing transactions...');
-    const signedTxs = [];
-    for(const chunk of stakersChunks) {
-      const tx = api.tx.sudo.sudo(api.tx.appPromotion.upgradeAccounts(chunk));
-      const signed = tx.sign(signer, {
-        blockHash: api.genesisHash,
-        genesisHash: api.genesisHash,
-        runtimeVersion: api.runtimeVersion,
-        nonce: nonce++,
-      });
-      signedTxs.push(signed);
-    }
-
-    // 6. Send all signed transactions
-    console.log('6. Sending transactions...');
-    const promises = signedTxs.map((tx) => api.rpc.author.submitAndWatchExtrinsic(tx));
-    // 6.1 Wait all transactions settled
-    console.log('6.1 Waiting all transactions settled...');
-    const res = await Promise.allSettled(promises);
-
-    console.log('Wait 5 blocks for transactions to be included in a block...');
-    await helper.wait.newBlocks(5);
-    // 6.2 Filter failed transactions
-    console.log('6.2 Getting failed transactions...');
-    const failedTx = res.filter((r) => r.status == 'rejected') as PromiseRejectedResult[];
-    console.log('6.2. total failedTxs:', failedTx.length);
-
-    // 6.3 Log the reasons of failed tx
-    for(const tx of failedTx) {
-      console.log(tx.reason);
-    }
-
-    // 7. Check balances for 10 blocks:
-    console.log('7. Check balances...');
-    let blocksLeft = 10;
-    let notMigrated = stakers;
-    const suspiciousAccounts = [];
-    do {
-      console.log('blocks left:', blocksLeft);
-      const _notMigrated: string[] = [];
-      console.log('accounts to migrate...', notMigrated.length);
-      for(const accountToMigrate of notMigrated) {
-        let accountMigrated = true;
-        // 7.0 get data from chainql:
-        const oldAccount = chainqlImportData.find(acc => acc.address === accountToMigrate);
-        if(!oldAccount) {
-          console.log('Cannot find old account data for', accountMigrated);
-          accountMigrated = false;
-          _notMigrated.push(accountToMigrate);
-          continue;
-        }
-
-        // 7.1 system.account
-        const balance = await api.query.system.account(accountToMigrate) as any;
-        // new balances
-        const free = balance.data.free;
-        const reserved = balance.data.reserved;
-        const frozen = balance.data.frozen;
-        // old balances
-        const oldFree = oldAccount.account.free;
-        const oldReserved = oldAccount.account.reserved;
-        const oldFrozen = oldAccount.account.fee_frozen;
-        // asserts new = old
-        if(oldFree.toString() !== free.toString()) {
-          console.log('Old free !== New free, which is probably not a problem', oldFree.toString(), free.toString());
-          suspiciousAccounts.push(accountToMigrate);
-        }
-        if(oldFrozen.toString() !== frozen.toString()) {
-          console.log('Old frozen !== New frozen, which is probably not a problem', oldFrozen.toString(), frozen.toString());
-          suspiciousAccounts.push(accountToMigrate);
-        }
-        if(oldReserved.toString() !== reserved.toString()) {
-          console.log('Old reserved !== New reserved, which is probably not a problem', oldReserved.toString(), reserved.toString());
-          suspiciousAccounts.push(accountToMigrate);
-        }
-
-        // 7.2 balances.locks: no id appstake
-        const locks = await helper.balance.getLocked(accountToMigrate);
-        const appPromoLocks = locks.filter(lock => lock.id === 'appstake');
-        if(appPromoLocks.length !== 0) {
-          console.log('Account still has app-promo lock');
-          accountMigrated = false;
-        }
-
-        // 7.3 balances.freezes set...
-        let freezes = await api.query.balances.freezes(accountToMigrate) as any;
-        freezes = freezes.map((freez: any) => ({id: freez.id.toString(), amount: freez.amount.toString()}));
-        if(!freezes) {
-          console.log('Account does not have freezes');
-          accountMigrated = false;
-        } else {
-          const oldAppPromoLocks = oldAccount.locks.filter(l => l.id === '0x6170707374616b65'); // get app promo locks
-          // should be only one freez for each account
-          if(freezes.length !== 1) {
-            console.log('freezes.length !== 1 and old appPromoLocks.length', freezes.length, oldAppPromoLocks.length);
-            accountMigrated = false;
-          } else {
-            const appPromoFreez = freezes[0];
-            // freez-amount should be equal to migrated lock amount
-            if(appPromoFreez.amount.toString() !== oldAppPromoLocks[0].amount.toString()) {
-              console.log('freezes amount !== old appPromoLocks amount', appPromoFreez.amount.toString(), oldAppPromoLocks[0].amount.toString());
-              accountMigrated = false;
-            }
-            // freez id should be correct
-            if(appPromoFreez.id !== '0x6170707374616b656170707374616b65') {
-              console.log('Got freez with incorrect id:', appPromoFreez.id);
-              accountMigrated = false;
-            }
-          }
-        }
-
-        // 7.4 Stakes number the same
-        const stakesNumber = await helper.staking.getStakesNumber({Substrate: accountToMigrate});
-        const oldStakesNumber = oldAccount.stakes ? Object.keys(oldAccount.stakes).length : 0;
-        if(stakesNumber.toString() !== oldStakesNumber.toString()) {
-          console.log('Old stakes number !== New stakes number', oldStakesNumber, stakesNumber);
-          accountMigrated = false;
-        }
-
-        // 7.5 Total pendingUnstake + total staked = old locked
-        const pendingUnstakes = await helper.staking.getPendingUnstake({Substrate: accountToMigrate});
-        const totalStaked = await helper.staking.getTotalStaked({Substrate: accountToMigrate});
-        const totalBalanceInAppPromo = pendingUnstakes + totalStaked;
-        if(totalBalanceInAppPromo.toString() !== oldAccount.balance.toString()) {
-          console.log('totalBalanceInAppPromo !== old locked in app promo', totalBalanceInAppPromo.toString(), oldAccount.balance.toString());
-          accountMigrated = false;
-        }
-
-        // 8 Add to not-migrated
-        if(!accountMigrated) {
-          console.log('Add to not migrated:', accountToMigrate);
-          _notMigrated.push(accountToMigrate);
-        }
-      }
-
-      blocksLeft--;
-      notMigrated = _notMigrated;
-      await helper.wait.newBlocks(1);
-    } while(blocksLeft > 0 && notMigrated.length !== 0);
-
-    console.log('Not migrated accounts...', notMigrated.length);
-    if(suspiciousAccounts.length > 0) {
-      console.log('Saving suspicious accounts to suspicious.json:');
-      fs.writeFileSync('./suspicious.json', JSON.stringify(suspiciousAccounts));
-    }
-    if(notMigrated.length > 0) {
-      console.log('Saving not migrated list to failed.json:');
-      notMigrated.forEach(console.log);
-      fs.writeFileSync('./failed.json', JSON.stringify(notMigrated));
-      process.exit(1);
-    } else {
-      console.log('Migration success');
-    }
-  }, options.wsEndpoint);
-};
-
-const chunk = <T>(arr: T[], size: number) =>
-  Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
-    arr.slice(i * size, i * size + size));
-
-const testChainqlData = (data: any) => {
-  const wrongData = [];
-  for(const account of data) {
-    try {
-      if(account.address == null) throw Error('no address in data');
-      if(account.balance == null) throw Error('no balance in data');
-      if(account.account == null) throw Error('no account in data');
-      if(account.account.fee_frozen == null) throw Error('no account.fee_frozen in data');
-      if(account.account.misc_frozen == null) throw Error('no account.misc_frozen in data');
-      if(account.account.free == null) throw Error('no account.free in data');
-      if(account.account.reserved == null) throw Error('no account.reserved in data');
-      if(account.locks == null) throw Error('no locks in data');
-      if(account.locks[0].amount == null) throw Error('no locks.amount in data');
-      if(account.locks[0].id == null) throw Error('no locks.id in data');
-    } catch (error) {
-      wrongData.push(account.address);
-      console.log((error as Error).message, account.address);
-    }
-    if(wrongData.length > 0) {
-      console.log(data);
-      throw Error('Chainql data not correct');
-    }
-  }
-  console.log('Chainql data correct');
-};
deletedjs-packages/tests/migrations/942057-appPromotion/stakersParser.jsonnetdiffbeforeafterboth
--- a/js-packages/tests/migrations/942057-appPromotion/stakersParser.jsonnet
+++ /dev/null
@@ -1,29 +0,0 @@
-function(chainUrl)
-
-  local
-    state = cql.chain(chainUrl).latest,
-    locked_balances = state.Balances.Locks._preloadKeys,
-    accountsRaw = state.System.Account._preloadKeys,
-    stakers = state.AppPromotion.Staked._preloadKeys,
-    unstakes = state.AppPromotion.PendingUnstake._preloadKeys,
-    locks = [
-      { [k]: std.filter(function(l) l.id == '0x6170707374616b65', locked_balances[k]) }
-      for k in std.objectFields(locked_balances)
-    ],
-    unstakersData = [
-      { [pair[0]]: { block: block, value: pair[1] } }
-
-      for block in std.objectFields(unstakes)
-      for pair in unstakes[block]
-    ],
-    non_empty_locks = std.prune(locks)
-  ;
-
-  std.map(function(a) {
-    address: std.objectFields(a)[0],
-    balance: a[std.objectFields(a)[0]][0].amount,
-    account: accountsRaw[std.objectFields(a)[0]].data,
-    locks: locked_balances[std.objectFields(a)[0]],
-    stakes: if std.objectHas(stakers, std.objectFields(a)[0]) then stakers[std.objectFields(a)[0]] else null,
-    unstakes: std.filterMap(function(b) std.objectHas(b, std.objectFields(a)[0]), function(c) std.objectValues(c)[0], unstakersData),
-  }, non_empty_locks)
deletedjs-packages/tests/migrations/correctStateAfterMaintenance.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/correctStateAfterMaintenance.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import config from '../config.js';
-import {usingPlaygrounds} from '@unique/test-utils/util.js';
-import type {u32} from '@polkadot/types-codec';
-
-const WS_ENDPOINT = config.substrateUrl;
-const DONOR_SEED = '//Alice';
-
-export const main = async(options: { wsEndpoint: string; donorSeed: string } = {
-  wsEndpoint: WS_ENDPOINT,
-  donorSeed: DONOR_SEED,
-}) => {
-  await usingPlaygrounds(async (helper, privateKey) => {
-    const api = helper.getApi();
-
-    if((await api.query.maintenance.enabled()).valueOf()) {
-      throw Error('The network is still in maintenance mode');
-    }
-
-    const pendingBlocks = (
-      await api.query.appPromotion.pendingUnstake.entries()
-    ).map(([k, _v]) =>
-      (k.args[0] as u32).toNumber());
-
-    const currentBlock = (await api.query.system.number() as u32).toNumber();
-
-    const filteredBlocks = pendingBlocks.filter(b => currentBlock > b);
-
-    if(filteredBlocks.length != 0) {
-      console.log(`During maintenance mode, ${filteredBlocks.length} block(s) were not processed. Number(s): ${filteredBlocks}`);
-    } else {
-      console.log('Nothing to change');
-      return;
-    }
-
-    const skippedBlocks = chunk(filteredBlocks, 10);
-
-    const signer = await privateKey(options.donorSeed);
-
-    const txs = skippedBlocks.map((b) =>
-      api.tx.sudo.sudo(api.tx.appPromotion.forceUnstake(b)));
-
-
-    const promises = txs.map((tx) => () => helper.signTransaction(signer, tx));
-
-    await Promise.allSettled(promises.map((p) => p()));
-
-    const failedBlocks: number[] = [];
-    let isSuccess = true;
-
-    for(const b of filteredBlocks) {
-      if(((await api.query.appPromotion.pendingUnstake(b)).toJSON() as any[]).length != 0) {
-        failedBlocks.push(b);
-        isSuccess = false;
-      }
-    }
-
-    if(isSuccess) {
-      console.log('Done. %d block(s) were processed.', filteredBlocks.length);
-    } else {
-      throw new Error(`Something went wrong. Block(s) have not been processed: ${failedBlocks}`);
-    }
-
-
-  }, options.wsEndpoint);
-};
-
-const chunk = <T>(arr: T[], size: number) =>
-  Array.from({length: Math.ceil(arr.length / size)}, (_: any, i: number) =>
-    arr.slice(i * size, i * size + size));
deletedjs-packages/tests/migrations/index.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import {migration as locksToFreezesMigration} from './942057-appPromotion/index.js';
-export interface Migration {
-  before: () => Promise<void>,
-  after: () => Promise<void>,
-}
-
-export const migrations: {[key: string]: Migration} = {
-  'v942057': locksToFreezesMigration,
-};
\ No newline at end of file
deletedjs-packages/tests/migrations/runCheckState.tsdiffbeforeafterboth
--- a/js-packages/tests/migrations/runCheckState.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import {main} from './correctStateAfterMaintenance.js';
-
-main({
-  wsEndpoint: process.env.WS_RPC!,
-  donorSeed: process.env.SUPERUSER_SEED!,
-}).then(() => process.exit(0))
-  .catch((e) => {
-    console.error(e);
-    process.exit(1);
-  });
modifiedjs-packages/tests/sub/appPromotion/appPromotion.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/appPromotion/appPromotion.seqtest.ts
+++ b/js-packages/tests/sub/appPromotion/appPromotion.seqtest.ts
@@ -16,7 +16,7 @@
 
 import type {IKeyringPair} from '@polkadot/types/types';
 import {itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '@unique/test-utils/util.js';
-import {expect} from '../../eth/util/index.js';
+import {expect} from '@unique/test-utils/eth/util.js';
 
 let superuser: IKeyringPair;
 let donor: IKeyringPair;
modifiedjs-packages/tests/sub/appPromotion/appPromotion.test.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/appPromotion/appPromotion.test.ts
+++ b/js-packages/tests/sub/appPromotion/appPromotion.test.ts
@@ -19,7 +19,7 @@
   itSub, usingPlaygrounds, Pallets, requirePalletsOrSkip, LOCKING_PERIOD, UNLOCKING_PERIOD,
 } from '@unique/test-utils/util.js';
 import {DevUniqueHelper} from '@unique/test-utils';
-import {itEth, expect, SponsoringMode} from '../../eth/util/index.js';
+import {itEth, expect, SponsoringMode} from '@unique/test-utils/eth/util.js';
 
 let donor: IKeyringPair;
 let palletAdmin: IKeyringPair;
modifiedjs-packages/tests/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth
--- a/js-packages/tests/sub/nesting/nesting.negative.test.ts
+++ b/js-packages/tests/sub/nesting/nesting.negative.test.ts
@@ -17,7 +17,7 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import {expect, itSub, Pallets, usingPlaygrounds} from '@unique/test-utils/util.js';
 import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '@unique-nft/playgrounds/unique.js';
-import {itEth} from '../../eth/util/index.js';
+import {itEth} from '@unique/test-utils/eth/util.js';
 
 let alice: IKeyringPair;
 let bob: IKeyringPair;
modifiedjs-packages/tests/transfer.test.tsdiffbeforeafterboth
before · js-packages/tests/transfer.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import type {IKeyringPair} from '@polkadot/types/types';18import {itEth, usingEthPlaygrounds} from './eth/util/index.js';19import {itSub, Pallets, usingPlaygrounds, expect} from '@unique/test-utils/util.js';20import {NON_EXISTENT_COLLECTION_ID} from '@unique-nft/playgrounds/types.js';2122describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {23  let donor: IKeyringPair;24  let alice: IKeyringPair;25  let bob: IKeyringPair;2627  before(async () => {28    await usingPlaygrounds(async (helper, privateKey) => {29      donor = await privateKey({url: import.meta.url});30      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);31    });32  });3334  itSub('Balance transfers and check balance', async ({helper}) => {35    const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address);36    const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);3738    expect(await helper.balance.transferToSubstrate(alice, bob.address, 1n)).to.be.true;3940    const alicesBalanceAfter = await helper.balance.getSubstrate(alice.address);41    const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);4243    expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;44    expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;45  });4647  itSub('Inability to pay fees error message is correct', async ({helper}) => {48    const [zero] = await helper.arrange.createAccounts([0n], donor);4950    // console.error = () => {};51    // The following operation throws an error into the console and the logs. Pay it no heed as long as the test succeeds.52    await expect(helper.balance.transferToSubstrate(zero, donor.address, 1n))53      .to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');54  });5556  itSub('[nft] User can transfer owned token', async ({helper}) => {57    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-1-NFT', description: '', tokenPrefix: 'T'});58    const nft = await collection.mintToken(alice);5960    await nft.transfer(alice, {Substrate: bob.address});61    expect(await nft.getOwner()).to.be.deep.equal({Substrate: bob.address});62  });6364  itSub('[fungible] User can transfer owned token', async ({helper}) => {65    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-1-FT', description: '', tokenPrefix: 'T'});66    await collection.mint(alice, 10n);6768    await collection.transfer(alice, {Substrate: bob.address}, 9n);69    expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);70    expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);71  });7273  itSub.ifWithPallets('[refungible] User can transfer owned token', [Pallets.ReFungible], async ({helper}) => {74    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});75    const rft = await collection.mintToken(alice, 10n);7677    await rft.transfer(alice, {Substrate: bob.address}, 9n);78    expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);79    expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);80  });8182  itSub('[nft] Collection admin can transfer owned token', async ({helper}) => {83    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-2-NFT', description: '', tokenPrefix: 'T'});84    await collection.addAdmin(alice, {Substrate: bob.address});8586    const nft = await collection.mintToken(bob, {Substrate: bob.address});87    await nft.transfer(bob, {Substrate: alice.address});8889    expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});90  });9192  itSub('[fungible] Collection admin can transfer owned token', async ({helper}) => {93    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-2-FT', description: '', tokenPrefix: 'T'});94    await collection.addAdmin(alice, {Substrate: bob.address});9596    await collection.mint(bob, 10n, {Substrate: bob.address});97    await collection.transfer(bob, {Substrate: alice.address}, 1n);9899    expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(9n);100    expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n);101  });102103  itSub.ifWithPallets('[refungible] Collection admin can transfer owned token', [Pallets.ReFungible], async ({helper}) => {104    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-2-RFT', description: '', tokenPrefix: 'T'});105    await collection.addAdmin(alice, {Substrate: bob.address});106107    const rft = await collection.mintToken(bob, 10n, {Substrate: bob.address});108    await rft.transfer(bob, {Substrate: alice.address}, 1n);109110    expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(9n);111    expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(1n);112  });113});114115describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {116  let alice: IKeyringPair;117  let bob: IKeyringPair;118119  before(async () => {120    await usingPlaygrounds(async (helper, privateKey) => {121      const donor = await privateKey({url: import.meta.url});122      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);123    });124  });125126127  itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {128    await expect(helper.nft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))129      .to.be.rejectedWith(/common\.CollectionNotFound/);130  });131132  itSub('[fungible] Transfer with not existed collection_id', async ({helper}) => {133    await expect(helper.ft.transfer(alice, NON_EXISTENT_COLLECTION_ID, {Substrate: bob.address}))134      .to.be.rejectedWith(/common\.CollectionNotFound/);135  });136137  itSub.ifWithPallets('[refungible] Transfer with not existed collection_id', [Pallets.ReFungible], async ({helper}) => {138    await expect(helper.rft.transferToken(alice, NON_EXISTENT_COLLECTION_ID, 1, {Substrate: bob.address}))139      .to.be.rejectedWith(/common\.CollectionNotFound/);140  });141142  itSub('[nft] Transfer with deleted collection_id', async ({helper}) => {143    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-1-NFT', description: '', tokenPrefix: 'T'});144    const nft = await collection.mintToken(alice);145146    await nft.burn(alice);147    await collection.burn(alice);148149    await expect(nft.transfer(alice, {Substrate: bob.address}))150      .to.be.rejectedWith(/common\.CollectionNotFound/);151  });152153  itSub('[fungible] Transfer with deleted collection_id', async ({helper}) => {154    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-1-FT', description: '', tokenPrefix: 'T'});155    await collection.mint(alice, 10n);156157    await collection.burnTokens(alice, 10n);158    await collection.burn(alice);159160    await expect(collection.transfer(alice, {Substrate: bob.address}))161      .to.be.rejectedWith(/common\.CollectionNotFound/);162  });163164  itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => {165    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'});166    const rft = await collection.mintToken(alice, 10n);167168    await rft.burn(alice, 10n);169    await collection.burn(alice);170171    await expect(rft.transfer(alice, {Substrate: bob.address}))172      .to.be.rejectedWith(/common\.CollectionNotFound/);173  });174175  itSub('[nft] Transfer with not existed item_id', async ({helper}) => {176    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-2-NFT', description: '', tokenPrefix: 'T'});177    await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))178      .to.be.rejectedWith(/common\.TokenNotFound/);179  });180181  itSub('[fungible] Transfer with not existed item_id', async ({helper}) => {182    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-2-FT', description: '', tokenPrefix: 'T'});183    await expect(collection.transfer(alice, {Substrate: bob.address}))184      .to.be.rejectedWith(/common\.TokenValueTooLow/);185  });186187  itSub.ifWithPallets('[refungible] Transfer with not existed item_id', [Pallets.ReFungible], async ({helper}) => {188    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-2-RFT', description: '', tokenPrefix: 'T'});189    await expect(collection.transferToken(alice, 1, {Substrate: bob.address}))190      .to.be.rejectedWith(/common\.TokenValueTooLow/);191  });192193  itSub('Zero transfer NFT', async ({helper}) => {194    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});195    const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});196    const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});197    // 1. Zero transfer of own tokens allowed:198    await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);199    // 2. Zero transfer of non-owned tokens not allowed:200    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');201    // 3. Zero transfer of non-existing tokens not allowed:202    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');203    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});204    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});205    // 4. Storage is not corrupted:206    await tokenAlice.transfer(alice, {Substrate: bob.address});207    await tokenBob.transfer(bob, {Substrate: alice.address});208    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});209    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});210  });211212  itSub('[nft] Transfer with deleted item_id', async ({helper}) => {213    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});214    const nft = await collection.mintToken(alice);215216    await nft.burn(alice);217218    await expect(nft.transfer(alice, {Substrate: bob.address}))219      .to.be.rejectedWith(/common\.TokenNotFound/);220  });221222  itSub('[fungible] Transfer with deleted item_id', async ({helper}) => {223    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-3-FT', description: '', tokenPrefix: 'T'});224    await collection.mint(alice, 10n);225226    await collection.burnTokens(alice, 10n);227228    await expect(collection.transfer(alice, {Substrate: bob.address}))229      .to.be.rejectedWith(/common\.TokenValueTooLow/);230  });231232  itSub.ifWithPallets('[refungible] Transfer with deleted item_id', [Pallets.ReFungible], async ({helper}) => {233    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-3-RFT', description: '', tokenPrefix: 'T'});234    const rft = await collection.mintToken(alice, 10n);235236    await rft.burn(alice, 10n);237238    await expect(rft.transfer(alice, {Substrate: bob.address}))239      .to.be.rejectedWith(/common\.TokenValueTooLow/);240  });241242  itSub('[nft] Transfer with recipient that is not owner', async ({helper}) => {243    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-4-NFT', description: '', tokenPrefix: 'T'});244    const nft = await collection.mintToken(alice);245246    await expect(nft.transfer(bob, {Substrate: bob.address}))247      .to.be.rejectedWith(/common\.NoPermission/);248    expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address});249  });250251  itSub('[fungible] Transfer with recipient that is not owner', async ({helper}) => {252    const collection = await helper.ft.mintCollection(alice, {name: 'Transfer-Neg-4-FT', description: '', tokenPrefix: 'T'});253    await collection.mint(alice, 10n);254255    await expect(collection.transfer(bob, {Substrate: bob.address}, 9n))256      .to.be.rejectedWith(/common\.TokenValueTooLow/);257    expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n);258    expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(10n);259  });260261  itSub.ifWithPallets('[refungible] Transfer with recipient that is not owner', [Pallets.ReFungible], async ({helper}) => {262    const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-1-RFT', description: '', tokenPrefix: 'T'});263    const rft = await collection.mintToken(alice, 10n);264265    await expect(rft.transfer(bob, {Substrate: bob.address}, 9n))266      .to.be.rejectedWith(/common\.TokenValueTooLow/);267    expect(await rft.getBalance({Substrate: bob.address})).to.be.equal(0n);268    expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(10n);269  });270});271272describe('Transfers to self (potentially over substrate-evm boundary)', () => {273  let donor: IKeyringPair;274275  before(async function() {276    await usingEthPlaygrounds(async (_, privateKey) => {277      donor = await privateKey({url: import.meta.url});278    });279  });280281  itEth('Transfers to self. In case of same frontend', async ({helper}) => {282    const [owner] = await helper.arrange.createAccounts([10n], donor);283    const collection = await helper.ft.mintCollection(owner, {});284    await collection.mint(owner, 100n);285286    const ownerProxy = helper.address.substrateToEth(owner.address);287288    // transfer to own proxy289    await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);290    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);291    expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);292293    // transfer-from own proxy to own proxy again294    await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Ethereum: ownerProxy}, 5n);295    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);296    expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);297  });298299  itEth('Transfers to self. In case of substrate-evm boundary', async ({helper}) => {300    const [owner] = await helper.arrange.createAccounts([10n], donor);301    const collection = await helper.ft.mintCollection(owner, {});302    await collection.mint(owner, 100n);303304    const ownerProxy = helper.address.substrateToEth(owner.address);305306    // transfer to own proxy307    await collection.transfer(owner, {Ethereum: ownerProxy}, 10n);308    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(90n);309    expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(10n);310311    // transfer-from own proxy to self312    await collection.transferFrom(owner, {Ethereum: ownerProxy}, {Substrate: owner.address}, 5n);313    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(95n);314    expect(await collection.getBalance({Ethereum: ownerProxy})).to.be.equal(5n);315  });316317  itEth('Transfers to self. In case of inside substrate-evm', async ({helper}) => {318    const [owner] = await helper.arrange.createAccounts([10n], donor);319    const collection = await helper.ft.mintCollection(owner, {});320    await collection.mint(owner, 100n);321322    // transfer to self again323    await collection.transfer(owner, {Substrate: owner.address}, 10n);324    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);325326    // transfer-from self to self again327    await collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 5n);328    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(100n);329  });330331  itEth('Transfers to self. In case of inside substrate-evm when not enought "Fungibles"', async ({helper}) => {332    const [owner] = await helper.arrange.createAccounts([10n], donor);333    const collection = await helper.ft.mintCollection(owner, {});334    await collection.mint(owner, 10n);335336    // transfer to self again337    await expect(collection.transfer(owner, {Substrate: owner.address}, 11n))338      .to.be.rejectedWith(/common\.TokenValueTooLow/);339340    // transfer-from self to self again341    await expect(collection.transferFrom(owner, {Substrate: owner.address}, {Substrate: owner.address}, 12n))342      .to.be.rejectedWith(/common\.TokenValueTooLow/);343    expect(await collection.getBalance({Substrate: owner.address})).to.be.equal(10n);344  });345});
modifiedjs-packages/yarn.lockdiffbeforeafterboth
--- a/js-packages/yarn.lock
+++ b/js-packages/yarn.lock
@@ -1242,6 +1242,12 @@
   languageName: node
   linkType: hard
 
+"@unique-nft/evm-abi@workspace:*, @unique-nft/evm-abi@workspace:evm-abi":
+  version: 0.0.0-use.local
+  resolution: "@unique-nft/evm-abi@workspace:evm-abi"
+  languageName: unknown
+  linkType: soft
+
 "@unique-nft/opal-testnet-types@workspace:*, @unique-nft/opal-testnet-types@workspace:types":
   version: 0.0.0-use.local
   resolution: "@unique-nft/opal-testnet-types@workspace:types"
@@ -6011,6 +6017,7 @@
     "@types/node": ^20.8.10
     "@typescript-eslint/eslint-plugin": ^6.10.0
     "@typescript-eslint/parser": ^6.10.0
+    "@unique-nft/evm-abi": "workspace:*"
     "@unique-nft/opal-testnet-types": "workspace:*"
     "@unique-nft/playgrounds": "workspace:*"
     "@unique/test-utils": "workspace:*"