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

no changes

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
--- a/js-packages/tests/transfer.test.ts
+++ b/js-packages/tests/transfer.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 './eth/util/index.js';
+import {itEth, usingEthPlaygrounds} from '@unique/test-utils/eth/util.js';
 import {itSub, Pallets, usingPlaygrounds, expect} from '@unique/test-utils/util.js';
 import {NON_EXISTENT_COLLECTION_ID} from '@unique-nft/playgrounds/types.js';
 
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:*"