From 584b8cd3e79cc5a7ff4bd3b7e1f9084eafb7b79a Mon Sep 17 00:00:00 2001 From: AugustoL Date: Sat, 29 Nov 2025 10:28:39 -0300 Subject: [PATCH 001/103] wip --- hardhat-node-test/package-lock.json | 5846 +++++++++---------- src/components/common/AddressDisplay.tsx | 41 + src/components/common/ENSRecordsDisplay.tsx | 323 + src/components/common/SearchBox.tsx | 101 +- src/components/pages/Address.tsx | 23 +- src/hooks/useENS.ts | 178 + src/services/ENS/ENSService.ts | 547 ++ src/types/index.ts | 37 + 8 files changed, 4152 insertions(+), 2944 deletions(-) create mode 100644 src/components/common/ENSRecordsDisplay.tsx create mode 100644 src/hooks/useENS.ts create mode 100644 src/services/ENS/ENSService.ts diff --git a/hardhat-node-test/package-lock.json b/hardhat-node-test/package-lock.json index 827f185..855a0cb 100644 --- a/hardhat-node-test/package-lock.json +++ b/hardhat-node-test/package-lock.json @@ -1,2925 +1,2925 @@ { - "name": "hardhat-test", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "hardhat-test", - "version": "1.0.0", - "devDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.5", - "@nomicfoundation/hardhat-toolbox-viem": "^5.0.1", - "@types/node": "^22.19.1", - "forge-std": "github:foundry-rs/forge-std#v1.9.4", - "hardhat": "^3.0.15", - "typescript": "~5.8.0", - "viem": "^2.39.3" - } - }, - "node_modules/@actions/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", - "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@actions/exec": "^1.1.1", - "@actions/http-client": "^2.0.1" - } - }, - "node_modules/@actions/exec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@actions/io": "^1.0.1" - } - }, - "node_modules/@actions/http-client": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", - "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.25.4" - } - }, - "node_modules/@actions/io": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", - "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", - "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/hash": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", - "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/networks": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/transactions": "^5.8.0", - "@ethersproject/web": "^5.8.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", - "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/abstract-provider": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", - "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/rlp": "^5.8.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", - "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", - "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "bn.js": "^5.2.1" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", - "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", - "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bignumber": "^5.8.0" - } - }, - "node_modules/@ethersproject/hash": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", - "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/abstract-signer": "^5.8.0", - "@ethersproject/address": "^5.8.0", - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", - "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "js-sha3": "0.8.0" - } - }, - "node_modules/@ethersproject/logger": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", - "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT" - }, - "node_modules/@ethersproject/networks": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", - "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/properties": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", - "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/rlp": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", - "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/signing-key": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", - "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "bn.js": "^5.2.1", - "elliptic": "6.6.1", - "hash.js": "1.1.7" - } - }, - "node_modules/@ethersproject/strings": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", - "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/logger": "^5.8.0" - } - }, - "node_modules/@ethersproject/transactions": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", - "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/address": "^5.8.0", - "@ethersproject/bignumber": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/constants": "^5.8.0", - "@ethersproject/keccak256": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/rlp": "^5.8.0", - "@ethersproject/signing-key": "^5.8.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", - "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/base64": "^5.8.0", - "@ethersproject/bytes": "^5.8.0", - "@ethersproject/logger": "^5.8.0", - "@ethersproject/properties": "^5.8.0", - "@ethersproject/strings": "^5.8.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", - "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nomicfoundation/edr": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.14.tgz", - "integrity": "sha512-MGHY2x7JaNdkqlQxFBYoM7Miw2EqsQrI3ReVZMwLP5mULSRTAOnt3hCw6cnjXxGi991HnejNAedJofke6OdqqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.14", - "@nomicfoundation/edr-darwin-x64": "0.12.0-next.14", - "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.14", - "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.14", - "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.14", - "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.14", - "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.14" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.14.tgz", - "integrity": "sha512-sl0DibKSUOS7JXhUtaQ6FJUY+nk+uq5gx+Fyd9iiqs8awZPNn6KSuvV1EbWCi+yd3mrxgZ/wO8E77C1Dxj4xQA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.14.tgz", - "integrity": "sha512-lfmatc1MSOaw0rDFB+ynnAGz5TWm3hSeY/+zDpPZghMODZelXm4JCqF41CQ6paLsW3X/pXcHM1HUGCUBWeoI/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.14.tgz", - "integrity": "sha512-sWun3PhVgat8d4lg1d5MAXSIsFlSMBzvrpMSDFNOU9hPJEclSHbHBMRcarQuGqwm/5ZBzTwCS25u78A+UATTrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.14.tgz", - "integrity": "sha512-omWKioD8fFp7ayCeSDu2CqvG78+oYw8zdVECDwZVmE0jpszRCsTufNYflWRQnlGqH6GqjEUwq2c3yLxFgOTjFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.14.tgz", - "integrity": "sha512-vk0s4SaC7s1wa98W24a4zqunTK/yIcSEnsSLRM/Nl+JJs6iqS8tvmnh/BbFINORMBJ065OWc10qw2Lsbu/rxtg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.14.tgz", - "integrity": "sha512-/xKQD6c2RXQBIb30iTeh/NrMdYvHs6Nd+2UXS6wxlfX7GzRPOkpVDiDGD7Sda82JI459KH67dADOD6CpX8cpHQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.12.0-next.14", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.14.tgz", - "integrity": "sha512-GZcyGdOoLWnUtfPU+6B1vUi4fwf3bouSRf3xuKFHz3p/WNhpDK+8Esq3UmOmYAZWRgFT0ZR6XUk9H2owGDTVvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@nomicfoundation/hardhat-errors": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-errors/-/hardhat-errors-3.0.5.tgz", - "integrity": "sha512-8Ayqf6hFM1glmrSxrXgX6n2pn5uTlHNxEB8N5Me0DOeOGB67PRIrQdiO+RzUhrNW5YgWUNWBevOLQbW06uQ79g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/hardhat-utils": "^3.0.1" - } - }, - "node_modules/@nomicfoundation/hardhat-ignition": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-3.0.5.tgz", - "integrity": "sha512-ZTaGHdDDuHE5MjlRaSbSIOuTSZcJtVd/ShEyE6E1PEt0FLTcgYZu+NNCWRc2JZG6/Cix0PAO297y+yi+USNilA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.2", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/ignition-core": "^3.0.5", - "@nomicfoundation/ignition-ui": "^3.0.5", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "json5": "^2.2.3", - "prompts": "^2.4.2" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-verify": "^3.0.0", - "hardhat": "^3.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-ignition-viem": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-viem/-/hardhat-ignition-viem-3.0.5.tgz", - "integrity": "sha512-bK+Rmg7m6wJxoqXOTxl/HA6AakdS6OUJjGUUYxfFpuXCH9c4tW3Qp7fpgAhI0W3cCPAeT42OANSDlCH/MRZbBA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.2" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.5", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/hardhat-viem": "^3.0.0", - "@nomicfoundation/ignition-core": "^3.0.5", - "hardhat": "^3.0.0", - "viem": "^2.30.0" - } - }, - "node_modules/@nomicfoundation/hardhat-keystore": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-keystore/-/hardhat-keystore-3.0.3.tgz", - "integrity": "sha512-rkwfdy/GsX/2SV49RGBvMsCuR+SYGJQGD3wcrS5m2Cyap5eQFEgKZbqpua6YQRA2raxRmVVH6antIIftgBFXAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/hashes": "1.7.1", - "@nomicfoundation/hardhat-errors": "^3.0.0", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/hardhat-zod-utils": "^3.0.0", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "zod": "^3.23.8" - }, - "peerDependencies": { - "hardhat": "^3.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-3.0.3.tgz", - "integrity": "sha512-FqXD8CPFNdluEhELqNV/Q0grOQtlwRWr28LW+/NTas3rrDAXpNOIPCCq3RIXJIqsdbNPQsG2FpnfKj9myqIsKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.5", - "@nomicfoundation/hardhat-utils": "^3.0.5" - }, - "peerDependencies": { - "hardhat": "^3.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-node-test-reporter": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-reporter/-/hardhat-node-test-reporter-3.0.1.tgz", - "integrity": "sha512-p6yNKZFnJ2OMplXx7zi45KGWr4hr/qMkg+gTuSSLLlph7NL1DGjGG+N6GrZs46AGSrsnYEocKXGnavl92dxEig==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@actions/core": "^1.10.1", - "chalk": "^5.3.0", - "jest-diff": "^29.7.0" - } - }, - "node_modules/@nomicfoundation/hardhat-node-test-runner": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-runner/-/hardhat-node-test-runner-3.0.7.tgz", - "integrity": "sha512-MwYZef9JwUl9HaA+rZDsXWEWdpeBfnW5YNB0kN9WUkEiPPoST4LGE/56+BtkmV487Mkt2yvuF0x73YppvX/ydA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.2", - "@nomicfoundation/hardhat-node-test-reporter": "^3.0.0", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/hardhat-zod-utils": "^3.0.0", - "tsx": "^4.19.3", - "zod": "^3.23.8" - }, - "peerDependencies": { - "hardhat": "^3.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-toolbox-viem": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-5.0.1.tgz", - "integrity": "sha512-NhPQjHwTk356k6WS7tPeEWS5ymtlZe2lzcZzvgd2AD7wrMXE/zUu5qacXgwPq/M6HVEczSpuFeu+/koQgA2pbA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@nomicfoundation/hardhat-ignition": "^3.0.0", - "@nomicfoundation/hardhat-ignition-viem": "^3.0.0", - "@nomicfoundation/hardhat-keystore": "^3.0.0", - "@nomicfoundation/hardhat-network-helpers": "^3.0.0", - "@nomicfoundation/hardhat-node-test-runner": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^3.0.0", - "@nomicfoundation/hardhat-viem": "^3.0.0", - "@nomicfoundation/hardhat-viem-assertions": "^3.0.0", - "@nomicfoundation/ignition-core": "^3.0.0", - "hardhat": "^3.0.0", - "viem": "^2.30.0" - } - }, - "node_modules/@nomicfoundation/hardhat-utils": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-3.0.5.tgz", - "integrity": "sha512-5zkQSuSxkwK7fQxKswJ1GGc/3AuWBSmxA7GhczTPLx28dAXQnubRU8nA48SkCkKesJq5x4TROP+XheSE2VkLUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@streamparser/json-node": "^0.0.22", - "debug": "^4.3.2", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^2.2.1", - "fast-equals": "^5.0.1", - "json-stream-stringify": "^3.1.6", - "rfdc": "^1.3.1", - "undici": "^6.16.1" - } - }, - "node_modules/@nomicfoundation/hardhat-utils/node_modules/undici": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", - "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/@nomicfoundation/hardhat-verify": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-3.0.7.tgz", - "integrity": "sha512-2Px2Zldg2oRJvy7odx8hZ0lZ4yjkW8XLr6umqcKl5z36+XifKRanzd8phoLEGQ8SRBNaVsaw0EDHi9Q0QTUu3A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@ethersproject/abi": "^5.8.0", - "@nomicfoundation/hardhat-errors": "^3.0.3", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/hardhat-zod-utils": "^3.0.0", - "cbor2": "^1.9.0", - "chalk": "^5.3.0", - "debug": "^4.3.2", - "semver": "^7.6.3", - "zod": "^3.23.8" - }, - "peerDependencies": { - "hardhat": "^3.0.0" - } - }, - "node_modules/@nomicfoundation/hardhat-viem": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem/-/hardhat-viem-3.0.1.tgz", - "integrity": "sha512-sUyi3Xn31vItf925YRgHp7x6FIFfG9B+jacWYyJ0RBi7BWCrC/aSUX4jRRmpzaZ4opLQ8KXAZdxS91Yka7AYtw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.0", - "@nomicfoundation/hardhat-utils": "^3.0.5" - }, - "peerDependencies": { - "hardhat": "^3.0.0", - "viem": "^2.30.0" - } - }, - "node_modules/@nomicfoundation/hardhat-viem-assertions": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem-assertions/-/hardhat-viem-assertions-3.0.4.tgz", - "integrity": "sha512-MLImyHVuFEVNOcpJ0cjmpJ/IYj/mc2Kql6g9swX5Xtln13Gyv4jJFvoyjEalt8K9SYVTNY8kpDtVmQ2fP8BsDA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.5", - "@nomicfoundation/hardhat-utils": "^3.0.5" - }, - "peerDependencies": { - "@nomicfoundation/hardhat-viem": "^3.0.0", - "hardhat": "^3.0.0", - "viem": "^2.30.0" - } - }, - "node_modules/@nomicfoundation/hardhat-zod-utils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-zod-utils/-/hardhat-zod-utils-3.0.1.tgz", - "integrity": "sha512-I6/pyYiS9p2lLkzQuedr1ScMocH+ew8l233xTi+LP92gjEiviJDxselpkzgU01MUM0t6BPpfP8yMO958LDEJVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/hardhat-errors": "^3.0.0", - "@nomicfoundation/hardhat-utils": "^3.0.2" - }, - "peerDependencies": { - "zod": "^3.23.8" - } - }, - "node_modules/@nomicfoundation/ignition-core": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-3.0.5.tgz", - "integrity": "sha512-pD3IHmePTkqwbhOaUwnSYhc9PCn2e9kFYi5nvWQFGEN3pjJ+EJeMyG0QWDJQU7beBeKNxbnb1SMPY+CBN5F+kA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/address": "5.6.1", - "@nomicfoundation/hardhat-errors": "^3.0.2", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/solidity-analyzer": "^0.1.1", - "cbor2": "^1.9.0", - "debug": "^4.3.2", - "ethers": "^6.14.0", - "immer": "10.0.2", - "lodash-es": "4.17.21", - "ndjson": "2.0.0" - } - }, - "node_modules/@nomicfoundation/ignition-core/node_modules/@ethersproject/address": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", - "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.6.2", - "@ethersproject/bytes": "^5.6.1", - "@ethersproject/keccak256": "^5.6.1", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.1" - } - }, - "node_modules/@nomicfoundation/ignition-ui": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-3.0.5.tgz", - "integrity": "sha512-lRvbvW8hCTGs2J8w71PJRfjfs3KwVrCQ/kvmCMq3sOS7yorVYqxUw36ERvjFa1pEwc+gER/xoUycRBhfRZ3NAA==", - "dev": true - }, - "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", - "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - }, - "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", - "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", - "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", - "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", - "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", - "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", - "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", - "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@sentry/core": { - "version": "9.47.1", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.1.tgz", - "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@streamparser/json": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.22.tgz", - "integrity": "sha512-b6gTSBjJ8G8SuO3Gbbj+zXbVx8NSs1EbpbMKpzGLWMdkR+98McH9bEjSz3+0mPJf68c5nxa3CrJHp5EQNXM6zQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@streamparser/json-node": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.22.tgz", - "integrity": "sha512-sJT2ptNRwqB1lIsQrQlCoWk5rF4tif9wDh+7yluAGijJamAhrHGYpFB/Zg3hJeceoZypi74ftXk8DHzwYpbZSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@streamparser/json": "^0.0.22" - } - }, - "node_modules/@types/node": { - "version": "22.19.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz", - "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/abitype": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.1.0.tgz", - "integrity": "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3.22.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cbor2": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/cbor2/-/cbor2-1.12.0.tgz", - "integrity": "sha512-3Cco8XQhi27DogSp9Ri6LYNZLi/TBY/JVnDe+mj06NkBjW/ZYOtekaEU4wZ4xcRMNrFkDv8KNtOAqHyDfz3lYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.7" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", - "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-equals": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.3.tgz", - "integrity": "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/forge-std": { - "version": "1.9.4", - "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#1eea5bae12ae557d589f9f0f0edae2faa47cb262", - "dev": true, - "license": "(Apache-2.0 OR MIT)" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-tsconfig": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", - "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/hardhat": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.0.15.tgz", - "integrity": "sha512-cXxaeSxFJ+u0MfbvWsS3Gdr7/uP7wjo4xviYcGdu9AKtwY6YsU+v0quK/j1NWmvO1Y4gk350SdZzQw++hJy4LA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nomicfoundation/edr": "0.12.0-next.14", - "@nomicfoundation/hardhat-errors": "^3.0.4", - "@nomicfoundation/hardhat-utils": "^3.0.5", - "@nomicfoundation/hardhat-zod-utils": "^3.0.1", - "@nomicfoundation/solidity-analyzer": "^0.1.1", - "@sentry/core": "^9.4.0", - "adm-zip": "^0.4.16", - "chalk": "^5.3.0", - "chokidar": "^4.0.3", - "debug": "^4.3.2", - "enquirer": "^2.3.0", - "ethereum-cryptography": "^2.2.1", - "micro-eth-signer": "^0.14.0", - "p-map": "^7.0.2", - "resolve.exports": "^2.0.3", - "semver": "^7.6.3", - "tsx": "^4.19.3", - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "bin": { - "hardhat": "dist/src/cli.js" - } - }, - "node_modules/hardhat/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/immer": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz", - "integrity": "sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/isows": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", - "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/js-sha3": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stream-stringify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", - "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=7.10.1" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "dev": true, - "license": "MIT" - }, - "node_modules/micro-eth-signer": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", - "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "micro-packed": "~0.7.2" - } - }, - "node_modules/micro-eth-signer/node_modules/@noble/curves": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", - "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.2" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-eth-signer/node_modules/@noble/hashes": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", - "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-packed": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", - "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/micro-packed/node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ndjson": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", - "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.5", - "readable-stream": "^3.6.0", - "split2": "^3.0.0", - "through2": "^4.0.0" - }, - "bin": { - "ndjson": "cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ox": { - "version": "0.9.6", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.6.tgz", - "integrity": "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.0.9", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/ox/node_modules/@adraffy/ens-normalize": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", - "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ox/node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "dev": true, - "license": "ISC", - "dependencies": { - "readable-stream": "^3.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "3" - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.20.6", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", - "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.25.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/viem": { - "version": "2.39.3", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.39.3.tgz", - "integrity": "sha512-s11rPQRvUEdc5qHK3xT4fIk4qvgPAaLwaTFq+EbFlcJJD+Xn3R4mc9H6B6fquEiHl/mdsdbG/uKCnYpoNtHNHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.9.1", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0", - "abitype": "1.1.0", - "isows": "1.0.7", - "ox": "0.9.6", - "ws": "8.18.3" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/viem/node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } + "name": "hardhat-node-test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hardhat-node-test", + "version": "1.0.0", + "devDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.5", + "@nomicfoundation/hardhat-toolbox-viem": "^5.0.1", + "@types/node": "^22.19.1", + "forge-std": "github:foundry-rs/forge-std#v1.9.4", + "hardhat": "^3.0.15", + "typescript": "~5.8.0", + "viem": "^2.39.3" + } + }, + "node_modules/@actions/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", + "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@actions/exec": "^1.1.1", + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/http-client": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", + "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tunnel": "^0.0.6", + "undici": "^5.25.4" + } + }, + "node_modules/@actions/io": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", + "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", + "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", + "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.12.0-next.14.tgz", + "integrity": "sha512-MGHY2x7JaNdkqlQxFBYoM7Miw2EqsQrI3ReVZMwLP5mULSRTAOnt3hCw6cnjXxGi991HnejNAedJofke6OdqqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.14", + "@nomicfoundation/edr-darwin-x64": "0.12.0-next.14", + "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.14", + "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.14", + "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.14", + "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.14", + "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.14" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.12.0-next.14.tgz", + "integrity": "sha512-sl0DibKSUOS7JXhUtaQ6FJUY+nk+uq5gx+Fyd9iiqs8awZPNn6KSuvV1EbWCi+yd3mrxgZ/wO8E77C1Dxj4xQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.12.0-next.14.tgz", + "integrity": "sha512-lfmatc1MSOaw0rDFB+ynnAGz5TWm3hSeY/+zDpPZghMODZelXm4JCqF41CQ6paLsW3X/pXcHM1HUGCUBWeoI/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.12.0-next.14.tgz", + "integrity": "sha512-sWun3PhVgat8d4lg1d5MAXSIsFlSMBzvrpMSDFNOU9hPJEclSHbHBMRcarQuGqwm/5ZBzTwCS25u78A+UATTrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.12.0-next.14.tgz", + "integrity": "sha512-omWKioD8fFp7ayCeSDu2CqvG78+oYw8zdVECDwZVmE0jpszRCsTufNYflWRQnlGqH6GqjEUwq2c3yLxFgOTjFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.12.0-next.14.tgz", + "integrity": "sha512-vk0s4SaC7s1wa98W24a4zqunTK/yIcSEnsSLRM/Nl+JJs6iqS8tvmnh/BbFINORMBJ065OWc10qw2Lsbu/rxtg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.12.0-next.14.tgz", + "integrity": "sha512-/xKQD6c2RXQBIb30iTeh/NrMdYvHs6Nd+2UXS6wxlfX7GzRPOkpVDiDGD7Sda82JI459KH67dADOD6CpX8cpHQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.12.0-next.14", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.12.0-next.14.tgz", + "integrity": "sha512-GZcyGdOoLWnUtfPU+6B1vUi4fwf3bouSRf3xuKFHz3p/WNhpDK+8Esq3UmOmYAZWRgFT0ZR6XUk9H2owGDTVvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@nomicfoundation/hardhat-errors": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-errors/-/hardhat-errors-3.0.5.tgz", + "integrity": "sha512-8Ayqf6hFM1glmrSxrXgX6n2pn5uTlHNxEB8N5Me0DOeOGB67PRIrQdiO+RzUhrNW5YgWUNWBevOLQbW06uQ79g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-utils": "^3.0.1" + } + }, + "node_modules/@nomicfoundation/hardhat-ignition": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-3.0.5.tgz", + "integrity": "sha512-ZTaGHdDDuHE5MjlRaSbSIOuTSZcJtVd/ShEyE6E1PEt0FLTcgYZu+NNCWRc2JZG6/Cix0PAO297y+yi+USNilA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.2", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/ignition-core": "^3.0.5", + "@nomicfoundation/ignition-ui": "^3.0.5", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "json5": "^2.2.3", + "prompts": "^2.4.2" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-verify": "^3.0.0", + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-ignition-viem": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-viem/-/hardhat-ignition-viem-3.0.5.tgz", + "integrity": "sha512-bK+Rmg7m6wJxoqXOTxl/HA6AakdS6OUJjGUUYxfFpuXCH9c4tW3Qp7fpgAhI0W3cCPAeT42OANSDlCH/MRZbBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.2" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.5", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/hardhat-viem": "^3.0.0", + "@nomicfoundation/ignition-core": "^3.0.5", + "hardhat": "^3.0.0", + "viem": "^2.30.0" + } + }, + "node_modules/@nomicfoundation/hardhat-keystore": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-keystore/-/hardhat-keystore-3.0.3.tgz", + "integrity": "sha512-rkwfdy/GsX/2SV49RGBvMsCuR+SYGJQGD3wcrS5m2Cyap5eQFEgKZbqpua6YQRA2raxRmVVH6antIIftgBFXAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@noble/ciphers": "1.2.1", + "@noble/hashes": "1.7.1", + "@nomicfoundation/hardhat-errors": "^3.0.0", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/hardhat-zod-utils": "^3.0.0", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-3.0.3.tgz", + "integrity": "sha512-FqXD8CPFNdluEhELqNV/Q0grOQtlwRWr28LW+/NTas3rrDAXpNOIPCCq3RIXJIqsdbNPQsG2FpnfKj9myqIsKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.5", + "@nomicfoundation/hardhat-utils": "^3.0.5" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-node-test-reporter": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-reporter/-/hardhat-node-test-reporter-3.0.1.tgz", + "integrity": "sha512-p6yNKZFnJ2OMplXx7zi45KGWr4hr/qMkg+gTuSSLLlph7NL1DGjGG+N6GrZs46AGSrsnYEocKXGnavl92dxEig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@actions/core": "^1.10.1", + "chalk": "^5.3.0", + "jest-diff": "^29.7.0" + } + }, + "node_modules/@nomicfoundation/hardhat-node-test-runner": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-node-test-runner/-/hardhat-node-test-runner-3.0.7.tgz", + "integrity": "sha512-MwYZef9JwUl9HaA+rZDsXWEWdpeBfnW5YNB0kN9WUkEiPPoST4LGE/56+BtkmV487Mkt2yvuF0x73YppvX/ydA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.2", + "@nomicfoundation/hardhat-node-test-reporter": "^3.0.0", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/hardhat-zod-utils": "^3.0.0", + "tsx": "^4.19.3", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox-viem": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox-viem/-/hardhat-toolbox-viem-5.0.1.tgz", + "integrity": "sha512-NhPQjHwTk356k6WS7tPeEWS5ymtlZe2lzcZzvgd2AD7wrMXE/zUu5qacXgwPq/M6HVEczSpuFeu+/koQgA2pbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@nomicfoundation/hardhat-ignition": "^3.0.0", + "@nomicfoundation/hardhat-ignition-viem": "^3.0.0", + "@nomicfoundation/hardhat-keystore": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^3.0.0", + "@nomicfoundation/hardhat-node-test-runner": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^3.0.0", + "@nomicfoundation/hardhat-viem": "^3.0.0", + "@nomicfoundation/hardhat-viem-assertions": "^3.0.0", + "@nomicfoundation/ignition-core": "^3.0.0", + "hardhat": "^3.0.0", + "viem": "^2.30.0" + } + }, + "node_modules/@nomicfoundation/hardhat-utils": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-utils/-/hardhat-utils-3.0.5.tgz", + "integrity": "sha512-5zkQSuSxkwK7fQxKswJ1GGc/3AuWBSmxA7GhczTPLx28dAXQnubRU8nA48SkCkKesJq5x4TROP+XheSE2VkLUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json-node": "^0.0.22", + "debug": "^4.3.2", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^2.2.1", + "fast-equals": "^5.0.1", + "json-stream-stringify": "^3.1.6", + "rfdc": "^1.3.1", + "undici": "^6.16.1" + } + }, + "node_modules/@nomicfoundation/hardhat-utils/node_modules/undici": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", + "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/@nomicfoundation/hardhat-verify": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-3.0.7.tgz", + "integrity": "sha512-2Px2Zldg2oRJvy7odx8hZ0lZ4yjkW8XLr6umqcKl5z36+XifKRanzd8phoLEGQ8SRBNaVsaw0EDHi9Q0QTUu3A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.8.0", + "@nomicfoundation/hardhat-errors": "^3.0.3", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/hardhat-zod-utils": "^3.0.0", + "cbor2": "^1.9.0", + "chalk": "^5.3.0", + "debug": "^4.3.2", + "semver": "^7.6.3", + "zod": "^3.23.8" + }, + "peerDependencies": { + "hardhat": "^3.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem/-/hardhat-viem-3.0.1.tgz", + "integrity": "sha512-sUyi3Xn31vItf925YRgHp7x6FIFfG9B+jacWYyJ0RBi7BWCrC/aSUX4jRRmpzaZ4opLQ8KXAZdxS91Yka7AYtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.0", + "@nomicfoundation/hardhat-utils": "^3.0.5" + }, + "peerDependencies": { + "hardhat": "^3.0.0", + "viem": "^2.30.0" + } + }, + "node_modules/@nomicfoundation/hardhat-viem-assertions": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-viem-assertions/-/hardhat-viem-assertions-3.0.4.tgz", + "integrity": "sha512-MLImyHVuFEVNOcpJ0cjmpJ/IYj/mc2Kql6g9swX5Xtln13Gyv4jJFvoyjEalt8K9SYVTNY8kpDtVmQ2fP8BsDA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.5", + "@nomicfoundation/hardhat-utils": "^3.0.5" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-viem": "^3.0.0", + "hardhat": "^3.0.0", + "viem": "^2.30.0" + } + }, + "node_modules/@nomicfoundation/hardhat-zod-utils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-zod-utils/-/hardhat-zod-utils-3.0.1.tgz", + "integrity": "sha512-I6/pyYiS9p2lLkzQuedr1ScMocH+ew8l233xTi+LP92gjEiviJDxselpkzgU01MUM0t6BPpfP8yMO958LDEJVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/hardhat-errors": "^3.0.0", + "@nomicfoundation/hardhat-utils": "^3.0.2" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@nomicfoundation/ignition-core": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-3.0.5.tgz", + "integrity": "sha512-pD3IHmePTkqwbhOaUwnSYhc9PCn2e9kFYi5nvWQFGEN3pjJ+EJeMyG0QWDJQU7beBeKNxbnb1SMPY+CBN5F+kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethersproject/address": "5.6.1", + "@nomicfoundation/hardhat-errors": "^3.0.2", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/solidity-analyzer": "^0.1.1", + "cbor2": "^1.9.0", + "debug": "^4.3.2", + "ethers": "^6.14.0", + "immer": "10.0.2", + "lodash-es": "4.17.21", + "ndjson": "2.0.0" + } + }, + "node_modules/@nomicfoundation/ignition-core/node_modules/@ethersproject/address": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz", + "integrity": "sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.1" + } + }, + "node_modules/@nomicfoundation/ignition-ui": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-3.0.5.tgz", + "integrity": "sha512-lRvbvW8hCTGs2J8w71PJRfjfs3KwVrCQ/kvmCMq3sOS7yorVYqxUw36ERvjFa1pEwc+gER/xoUycRBhfRZ3NAA==", + "dev": true + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.1.tgz", + "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@streamparser/json": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.22.tgz", + "integrity": "sha512-b6gTSBjJ8G8SuO3Gbbj+zXbVx8NSs1EbpbMKpzGLWMdkR+98McH9bEjSz3+0mPJf68c5nxa3CrJHp5EQNXM6zQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@streamparser/json-node": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@streamparser/json-node/-/json-node-0.0.22.tgz", + "integrity": "sha512-sJT2ptNRwqB1lIsQrQlCoWk5rF4tif9wDh+7yluAGijJamAhrHGYpFB/Zg3hJeceoZypi74ftXk8DHzwYpbZSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@streamparser/json": "^0.0.22" + } + }, + "node_modules/@types/node": { + "version": "22.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz", + "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/abitype": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.1.0.tgz", + "integrity": "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cbor2": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/cbor2/-/cbor2-1.12.0.tgz", + "integrity": "sha512-3Cco8XQhi27DogSp9Ri6LYNZLi/TBY/JVnDe+mj06NkBjW/ZYOtekaEU4wZ4xcRMNrFkDv8KNtOAqHyDfz3lYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.7" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", + "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/ethers/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.3.tgz", + "integrity": "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/forge-std": { + "version": "1.9.4", + "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#1eea5bae12ae557d589f9f0f0edae2faa47cb262", + "dev": true, + "license": "(Apache-2.0 OR MIT)" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/hardhat": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-3.0.15.tgz", + "integrity": "sha512-cXxaeSxFJ+u0MfbvWsS3Gdr7/uP7wjo4xviYcGdu9AKtwY6YsU+v0quK/j1NWmvO1Y4gk350SdZzQw++hJy4LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nomicfoundation/edr": "0.12.0-next.14", + "@nomicfoundation/hardhat-errors": "^3.0.4", + "@nomicfoundation/hardhat-utils": "^3.0.5", + "@nomicfoundation/hardhat-zod-utils": "^3.0.1", + "@nomicfoundation/solidity-analyzer": "^0.1.1", + "@sentry/core": "^9.4.0", + "adm-zip": "^0.4.16", + "chalk": "^5.3.0", + "chokidar": "^4.0.3", + "debug": "^4.3.2", + "enquirer": "^2.3.0", + "ethereum-cryptography": "^2.2.1", + "micro-eth-signer": "^0.14.0", + "p-map": "^7.0.2", + "resolve.exports": "^2.0.3", + "semver": "^7.6.3", + "tsx": "^4.19.3", + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "bin": { + "hardhat": "dist/src/cli.js" + } + }, + "node_modules/hardhat/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/immer": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz", + "integrity": "sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ndjson": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", + "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "json-stringify-safe": "^5.0.1", + "minimist": "^1.2.5", + "readable-stream": "^3.6.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "ndjson": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ox": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.6.tgz", + "integrity": "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.9", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ox/node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ox/node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ox/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/viem": { + "version": "2.39.3", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.39.3.tgz", + "integrity": "sha512-s11rPQRvUEdc5qHK3xT4fIk4qvgPAaLwaTFq+EbFlcJJD+Xn3R4mc9H6B6fquEiHl/mdsdbG/uKCnYpoNtHNHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.1.0", + "isows": "1.0.7", + "ox": "0.9.6", + "ws": "8.18.3" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } } diff --git a/src/components/common/AddressDisplay.tsx b/src/components/common/AddressDisplay.tsx index bf1e503..ca1071b 100644 --- a/src/components/common/AddressDisplay.tsx +++ b/src/components/common/AddressDisplay.tsx @@ -6,6 +6,9 @@ import type { AddressTransactionsResult, Transaction, RPCMetadata, + ENSRecords, + ENSReverseResult, + DecodedContenthash, } from "../../types"; import { AppContext } from "../../context"; import { @@ -14,6 +17,7 @@ import { } from "wagmi"; import { parseEther, encodeFunctionData } from "viem"; import { RPCIndicator } from "./RPCIndicator"; +import ENSRecordsDisplay from "./ENSRecordsDisplay"; import { ConnectButton } from "@rainbow-me/rainbowkit"; @@ -27,6 +31,13 @@ interface AddressDisplayProps { metadata?: RPCMetadata; selectedProvider?: string | null; onProviderSelect?: (provider: string) => void; + // ENS props + ensName?: string | null; + reverseResult?: ENSReverseResult | null; + ensRecords?: ENSRecords | null; + decodedContenthash?: DecodedContenthash | null; + ensLoading?: boolean; + isMainnet?: boolean; } const AddressDisplay: React.FC = React.memo( @@ -40,6 +51,12 @@ const AddressDisplay: React.FC = React.memo( metadata, selectedProvider, onProviderSelect, + ensName, + reverseResult, + ensRecords, + decodedContenthash, + ensLoading = false, + isMainnet = true, }) => { const [storageSlot, setStorageSlot] = useState(""); const [storageValue, setStorageValue] = useState(""); @@ -331,6 +348,18 @@ const AddressDisplay: React.FC = React.memo( >
Address + {(ensName || reverseResult?.ensName) && ( + + {ensName || reverseResult?.ensName} + + )} {addressHash}
{metadata && selectedProvider !== undefined && onProviderSelect && ( @@ -435,6 +464,18 @@ const AddressDisplay: React.FC = React.memo( )} + {/* ENS Records Section */} + {(ensName || reverseResult?.ensName || ensLoading) && ( + + )} + {/* Contract Verification Details */} {isContract && (isVerified || parsedLocalData) && contractData && (
diff --git a/src/components/common/ENSRecordsDisplay.tsx b/src/components/common/ENSRecordsDisplay.tsx new file mode 100644 index 0000000..476c06a --- /dev/null +++ b/src/components/common/ENSRecordsDisplay.tsx @@ -0,0 +1,323 @@ +import React, { useState } from "react"; +import type { ENSRecords, ENSReverseResult, DecodedContenthash } from "../../types"; + +interface ENSRecordsDisplayProps { + ensName: string | null; + reverseResult?: ENSReverseResult | null; + records?: ENSRecords | null; + decodedContenthash?: DecodedContenthash | null; + loading?: boolean; + isMainnet?: boolean; +} + +const TEXT_RECORD_LABELS: Record = { + avatar: "Avatar", + email: "Email", + url: "Website", + description: "Description", + "com.twitter": "Twitter", + "com.github": "GitHub", + "com.discord": "Discord", + "org.telegram": "Telegram", + notice: "Notice", + keywords: "Keywords", + location: "Location", +}; + +const ENSRecordsDisplay: React.FC = ({ + ensName, + reverseResult, + records, + decodedContenthash, + loading = false, + isMainnet = true, +}) => { + const [showAllRecords, setShowAllRecords] = useState(false); + + // If not on mainnet, show a notice + if (!isMainnet) { + return ( +
+
+ ENS Records +
+
+ ENS records are only available on Ethereum Mainnet +
+
+ ); + } + + // If loading + if (loading) { + return ( +
+
+ ENS Records +
+
+ Loading ENS records... +
+
+ ); + } + + // No ENS name found + if (!ensName && !reverseResult?.ensName) { + return null; // Don't show the section if there's no ENS name + } + + const displayName = ensName || reverseResult?.ensName; + const hasTextRecords = records?.textRecords && Object.keys(records.textRecords).length > 0; + + return ( +
+
+ ENS Records +
+ + {/* Primary ENS Name */} +
+ ENS Name: + + + + {displayName} + + {reverseResult && ( + + {reverseResult.verified ? "Primary Name" : "Unverified"} + + )} + + +
+ + {/* Avatar */} + {records?.textRecords?.avatar && ( +
+ Avatar: + + {records.textRecords.avatar.startsWith("http") || + records.textRecords.avatar.startsWith("ipfs") ? ( + + ) : ( + {records.textRecords.avatar} + )} + +
+ )} + + {/* Contenthash */} + {records?.contenthash && ( +
+ Content Hash: + + {decodedContenthash ? ( + + ) : ( + + {records.contenthash.slice(0, 20)}... + + )} + +
+ )} + + {/* Text Records */} + {hasTextRecords && ( + <> +
setShowAllRecords(!showAllRecords)} + > + + Text Records ({Object.keys(records.textRecords).length}): + + + {showAllRecords ? "Hide" : "Show"} {showAllRecords ? "β–Ό" : "β–Ά"} + +
+ + {showAllRecords && ( +
+ {Object.entries(records.textRecords) + .filter(([key]) => key !== "avatar") // Avatar is displayed separately + .map(([key, value]) => ( +
+ + {TEXT_RECORD_LABELS[key] || key}: + + + {value.startsWith("http") ? ( + + {value.length > 50 ? value.slice(0, 50) + "..." : value} + + ) : key === "com.twitter" ? ( + + @{value.replace("@", "")} + + ) : key === "com.github" ? ( + + {value} + + ) : key === "email" ? ( + + {value} + + ) : ( + {value} + )} + +
+ ))} +
+ )} + + )} + + {/* Link to ENS app */} + {displayName && ( +
+ ENS App: + + + View on ENS App β†— + + +
+ )} +
+ ); +}; + +export default ENSRecordsDisplay; diff --git a/src/components/common/SearchBox.tsx b/src/components/common/SearchBox.tsx index 6272432..59003fb 100644 --- a/src/components/common/SearchBox.tsx +++ b/src/components/common/SearchBox.tsx @@ -1,10 +1,15 @@ -import React, { useState } from "react"; +import React, { useState, useContext } from "react"; import { useLocation, useNavigate } from "react-router-dom"; +import { AppContext } from "../../context"; +import { ENSService } from "../../services/ENS/ENSService"; const SearchBox = () => { const [searchTerm, setSearchTerm] = useState(""); + const [isResolving, setIsResolving] = useState(false); + const [error, setError] = useState(null); const navigate = useNavigate(); const location = useLocation(); + const { rpcUrls } = useContext(AppContext); // Extract chainId from the pathname (e.g., /1/blocks -> 1) const pathSegments = location.pathname.split("/").filter(Boolean); @@ -13,25 +18,59 @@ const SearchBox = () => { ? pathSegments[0] : undefined; - const handleSearch = (e: React.FormEvent) => { + const handleSearch = async (e: React.FormEvent) => { e.preventDefault(); if (!searchTerm.trim()) return; - // Basic routing logic placeholder - // In a real app, we would detect the type of input (address, tx, block) - // For now, we'll just log it or maybe navigate to a search result page if it existed. - // Since the user just asked for the UI, we'll keep the logic minimal but functional enough to show interaction. - console.log("Searching for:", searchTerm); - - // Example logic: - if (searchTerm.startsWith("0x")) { - if (searchTerm.length === 42) { - navigate(`/${chainId}/address/${searchTerm}`); - } else if (searchTerm.length === 66) { - navigate(`/${chainId}/tx/${searchTerm}`); + const term = searchTerm.trim(); + setError(null); + + // Check if it's an ENS name + if (ENSService.isENSName(term)) { + setIsResolving(true); + try { + // ENS resolution only works on mainnet (chainId 1) + // Use mainnet RPC even if viewing a different chain + const mainnetRpcUrls = rpcUrls[1]; + + if (!mainnetRpcUrls || mainnetRpcUrls.length === 0) { + setError("No Ethereum mainnet RPC configured"); + setIsResolving(false); + return; + } + + // Pass all RPC URLs for fallback support + const ensService = new ENSService(mainnetRpcUrls); + const resolvedAddress = await ensService.resolve(term); + + if (resolvedAddress) { + // Navigate to address page on the current chain (or mainnet if no chain selected) + const targetChainId = chainId || "1"; + navigate(`/${targetChainId}/address/${resolvedAddress}`, { + state: { ensName: term }, + }); + } else { + setError(`Could not resolve ENS name: ${term}`); + } + } catch (err) { + setError( + `Error resolving ENS: ${err instanceof Error ? err.message : "Unknown error"}`, + ); + } finally { + setIsResolving(false); + } + return; + } + + // Standard search logic for hex addresses/hashes + if (term.startsWith("0x")) { + if (term.length === 42) { + navigate(`/${chainId}/address/${term}`); + } else if (term.length === 66) { + navigate(`/${chainId}/tx/${term}`); } - } else if (!isNaN(Number(searchTerm))) { - navigate(`/${chainId}/block/${searchTerm}`); + } else if (!isNaN(Number(term))) { + navigate(`/${chainId}/block/${term}`); } }; @@ -41,14 +80,36 @@ const SearchBox = () => { setSearchTerm(e.target.value)} + onChange={(e) => { + setSearchTerm(e.target.value); + setError(null); + }} + disabled={isResolving} /> - + {error && ( +
+ {error} +
+ )}
); }; diff --git a/src/components/pages/Address.tsx b/src/components/pages/Address.tsx index 6dbff2a..bf21031 100644 --- a/src/components/pages/Address.tsx +++ b/src/components/pages/Address.tsx @@ -1,4 +1,4 @@ -import { useParams } from "react-router-dom"; +import { useParams, useLocation } from "react-router-dom"; import { useDataService } from "../../hooks/useDataService"; import { useEffect, useState } from "react"; import type { @@ -11,12 +11,14 @@ import AddressDisplay from "../common/AddressDisplay"; import Loader from "../common/Loader"; import { useProviderSelection } from "../../hooks/useProviderSelection"; import { useSelectedData } from "../../hooks/useSelectedData"; +import { useENS } from "../../hooks/useENS"; export default function Address() { const { chainId, address } = useParams<{ chainId?: string; address?: string; }>(); + const location = useLocation(); const numericChainId = Number(chainId) || 1; const dataService = useDataService(numericChainId); const [addressResult, setAddressResult] = @@ -38,6 +40,19 @@ export default function Address() { // Extract actual address data based on selected provider const addressData = useSelectedData(addressResult, selectedProvider); + // Get ENS name from navigation state (if user searched by ENS name) + const initialEnsName = (location.state as { ensName?: string })?.ensName; + + // Use ENS hook to get reverse lookup and records + const { + ensName, + reverseResult, + records: ensRecords, + decodedContenthash, + loading: ensLoading, + isMainnet, + } = useENS(address, numericChainId, initialEnsName); + useEffect(() => { if (!dataService || !address) { setLoading(false); @@ -165,6 +180,12 @@ export default function Address() { metadata={addressResult?.metadata} selectedProvider={selectedProvider} onProviderSelect={setSelectedProvider} + ensName={ensName} + reverseResult={reverseResult} + ensRecords={ensRecords} + decodedContenthash={decodedContenthash} + ensLoading={ensLoading} + isMainnet={isMainnet} /> ) : (

Address data not found

diff --git a/src/hooks/useENS.ts b/src/hooks/useENS.ts new file mode 100644 index 0000000..3b6fee3 --- /dev/null +++ b/src/hooks/useENS.ts @@ -0,0 +1,178 @@ +// src/hooks/useENS.ts +import { useState, useEffect, useContext, useCallback } from "react"; +import { AppContext } from "../context"; +import { ENSService } from "../services/ENS/ENSService"; +import type { ENSRecords, ENSReverseResult, DecodedContenthash } from "../types"; + +interface UseENSResult { + ensName: string | null; + reverseResult: ENSReverseResult | null; + records: ENSRecords | null; + decodedContenthash: DecodedContenthash | null; + loading: boolean; + error: string | null; + isMainnet: boolean; + refetch: () => void; +} + +/** + * Hook to fetch ENS data for an address + * @param address - The Ethereum address to look up + * @param chainId - The current chain ID (ENS only works on mainnet) + * @param initialEnsName - Optional ENS name if already known (e.g., from navigation state) + */ +export function useENS( + address: string | undefined, + chainId: number, + initialEnsName?: string, +): UseENSResult { + const { rpcUrls } = useContext(AppContext); + const [ensName, setEnsName] = useState(initialEnsName || null); + const [reverseResult, setReverseResult] = useState( + null, + ); + const [records, setRecords] = useState(null); + const [decodedContenthash, setDecodedContenthash] = + useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [fetchTrigger, setFetchTrigger] = useState(0); + + // Check if we're on mainnet (ENS only works on Ethereum mainnet) + const isMainnet = chainId === 1; + + const refetch = useCallback(() => { + setFetchTrigger((prev) => prev + 1); + }, []); + + useEffect(() => { + if (!address) { + setEnsName(null); + setReverseResult(null); + setRecords(null); + setDecodedContenthash(null); + return; + } + + // Always use mainnet RPC for ENS resolution + const mainnetRpcUrls = rpcUrls[1]; + + if (!mainnetRpcUrls || mainnetRpcUrls.length === 0) { + setError("No Ethereum mainnet RPC configured for ENS resolution"); + return; + } + + // Pass all RPC URLs for fallback support + const ensService = new ENSService(mainnetRpcUrls); + + const fetchENSData = async () => { + setLoading(true); + setError(null); + + try { + // If we have an initial ENS name, use it + // Otherwise, do a reverse lookup + let name: string | null = initialEnsName || null; + + if (!name) { + // Reverse resolve: address -> ENS name + const reverse = await ensService.reverseResolve(address); + setReverseResult(reverse); + name = reverse.ensName; + } else { + // If we have the name, verify it with forward resolution + const resolvedAddr = await ensService.resolve(name); + const verified = + resolvedAddr?.toLowerCase() === address.toLowerCase(); + setReverseResult({ ensName: name, verified }); + } + + setEnsName(name); + + // If we found an ENS name, fetch the full records + if (name) { + const ensRecords = await ensService.getRecords(name); + setRecords(ensRecords); + + // Decode contenthash if present + if (ensRecords.contenthash) { + const decoded = ensService.decodeContenthash(ensRecords.contenthash); + setDecodedContenthash(decoded); + } + } + } catch (err) { + console.error("Error fetching ENS data:", err); + setError(err instanceof Error ? err.message : "Unknown error"); + } finally { + setLoading(false); + } + }; + + fetchENSData(); + }, [address, rpcUrls, initialEnsName, fetchTrigger]); + + return { + ensName, + reverseResult, + records, + decodedContenthash, + loading, + error, + isMainnet, + refetch, + }; +} + +/** + * Hook to resolve an ENS name to an address + * @param ensName - The ENS name to resolve + */ +export function useENSResolve(ensName: string | undefined): { + address: string | null; + loading: boolean; + error: string | null; +} { + const { rpcUrls } = useContext(AppContext); + const [address, setAddress] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + if (!ensName || !ENSService.isENSName(ensName)) { + setAddress(null); + return; + } + + const mainnetRpcUrls = rpcUrls[1]; + + if (!mainnetRpcUrls || mainnetRpcUrls.length === 0) { + setError("No Ethereum mainnet RPC configured"); + return; + } + + const fetchAddress = async () => { + setLoading(true); + setError(null); + + try { + const ensService = new ENSService(mainnetRpcUrls); + const resolved = await ensService.resolve(ensName); + setAddress(resolved); + + if (!resolved) { + setError(`Could not resolve ENS name: ${ensName}`); + } + } catch (err) { + setError(err instanceof Error ? err.message : "Unknown error"); + } finally { + setLoading(false); + } + }; + + fetchAddress(); + }, [ensName, rpcUrls]); + + return { address, loading, error }; +} + +export default useENS; diff --git a/src/services/ENS/ENSService.ts b/src/services/ENS/ENSService.ts new file mode 100644 index 0000000..ed4886e --- /dev/null +++ b/src/services/ENS/ENSService.ts @@ -0,0 +1,547 @@ +// src/services/ENS/ENSService.ts +import { keccak256, toUtf8Bytes, AbiCoder, concat, zeroPadValue } from "ethers"; + +// ENS Contract addresses on Ethereum Mainnet +const ENS_REGISTRY_ADDRESS = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; +const PUBLIC_RESOLVER_ADDRESS = "0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"; + +// Function selectors +const SELECTORS = { + resolver: "0x0178b8bf", // resolver(bytes32 node) + addr: "0x3b3b57de", // addr(bytes32 node) + addrWithCoinType: "0xf1cb7e06", // addr(bytes32 node, uint256 coinType) + name: "0x691f3431", // name(bytes32 node) + text: "0x59d1d43c", // text(bytes32 node, string key) + contenthash: "0xbc1c58d1", // contenthash(bytes32 node) +}; + +// Common text record keys +export const TEXT_RECORD_KEYS = [ + "avatar", + "email", + "url", + "description", + "com.twitter", + "com.github", + "com.discord", + "org.telegram", + "notice", + "keywords", + "location", +]; + +export interface ENSRecords { + name?: string; + address?: string; + contenthash?: string; + textRecords: Record; +} + +export interface ENSResolveResult { + address: string; + ensName: string; + records?: ENSRecords; +} + +export interface ENSReverseResult { + ensName: string | null; + verified: boolean; // true if forward resolution matches +} + +export class ENSService { + private rpcUrls: string[]; + private abiCoder: AbiCoder; + + constructor(rpcUrl: string | string[]) { + this.rpcUrls = Array.isArray(rpcUrl) ? rpcUrl : [rpcUrl]; + this.abiCoder = new AbiCoder(); + } + + /** + * Normalize an ENS name according to UTS-46 + * Converts to lowercase and handles special characters + */ + private normalize(name: string): string { + // Basic normalization: lowercase and trim + // For full UTS-46 compliance, use a library like @adraffy/ens-normalize + return name.toLowerCase().trim(); + } + + /** + * Compute the namehash of an ENS name + * Follows ENS namehashing algorithm: recursively hash from right to left + */ + namehash(name: string): string { + if (!name || name === "") { + return "0x" + "0".repeat(64); + } + + const normalized = this.normalize(name); + const labels = normalized.split("."); + + let node = + "0x0000000000000000000000000000000000000000000000000000000000000000"; + + for (let i = labels.length - 1; i >= 0; i--) { + const label = labels[i]; + if (!label) continue; + + const labelHash = keccak256(toUtf8Bytes(label)); + // Concatenate node and labelHash as bytes, then hash + node = keccak256(concat([node, labelHash])); + } + + return node; + } + + /** + * Make an eth_call to the RPC endpoint with fallback support + */ + private async ethCall(to: string, data: string): Promise { + const errors: Error[] = []; + + for (const rpcUrl of this.rpcUrls) { + try { + console.log("ENS ethCall:", { rpcUrl, to, data }); + + const response = await fetch(rpcUrl, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "eth_call", + params: [{ to, data }, "latest"], + }), + }); + + const result = await response.json(); + console.log("ENS ethCall result:", result); + + if (result.error) { + console.error("ENS RPC error:", result.error); + errors.push(new Error(result.error.message || "RPC error")); + continue; // Try next RPC + } + + if (result.result === undefined || result.result === null) { + errors.push(new Error("no response")); + continue; // Try next RPC + } + + return result.result; + } catch (err) { + console.error("ENS ethCall fetch error:", err); + errors.push(err instanceof Error ? err : new Error(String(err))); + continue; // Try next RPC + } + } + + // All RPCs failed + throw errors[0] || new Error("All RPC endpoints failed"); + } + + /** + * Get the resolver address for an ENS name + */ + async getResolver(name: string): Promise { + const node = this.namehash(name); + console.log("ENS getResolver:", { name, node }); + const data = SELECTORS.resolver + node.slice(2); + + try { + const result = await this.ethCall(ENS_REGISTRY_ADDRESS, data); + + // Extract address from result (last 20 bytes of 32-byte response) + if ( + result === "0x" || + result === + "0x0000000000000000000000000000000000000000000000000000000000000000" + ) { + console.log("ENS getResolver: no resolver found"); + return null; + } + + const resolverAddress = "0x" + result.slice(-40); + console.log("ENS getResolver: found resolver", resolverAddress); + return resolverAddress; + } catch (err) { + console.error("ENS getResolver error:", err); + return null; + } + } + + /** + * Forward resolution: ENS name -> Ethereum address + */ + async resolve(name: string): Promise { + // First get the resolver for this name + const resolverAddress = await this.getResolver(name); + if (!resolverAddress) { + return null; + } + + const node = this.namehash(name); + const data = SELECTORS.addr + node.slice(2); + + try { + const result = await this.ethCall(resolverAddress, data); + + if ( + result === "0x" || + result === + "0x0000000000000000000000000000000000000000000000000000000000000000" + ) { + return null; + } + + // Extract address from result + const address = "0x" + result.slice(-40); + return address; + } catch { + return null; + } + } + + /** + * Reverse resolution: Ethereum address -> ENS name + * Uses the .addr.reverse domain + */ + async reverseResolve(address: string): Promise { + // Create the reverse lookup name:
.addr.reverse + const reverseAddress = address.toLowerCase().slice(2); // Remove 0x prefix + const reverseName = `${reverseAddress}.addr.reverse`; + + // Get the resolver for the reverse name + const resolverAddress = await this.getResolver(reverseName); + if (!resolverAddress) { + return { ensName: null, verified: false }; + } + + // Call name() on the resolver + const node = this.namehash(reverseName); + const data = SELECTORS.name + node.slice(2); + + try { + const result = await this.ethCall(resolverAddress, data); + + if (result === "0x" || result.length <= 2) { + return { ensName: null, verified: false }; + } + + // Decode the string result + const ensName = this.decodeString(result); + + if (!ensName) { + return { ensName: null, verified: false }; + } + + // Verify the forward resolution matches + const forwardAddress = await this.resolve(ensName); + const verified = + forwardAddress?.toLowerCase() === address.toLowerCase(); + + return { ensName, verified }; + } catch { + return { ensName: null, verified: false }; + } + } + + /** + * Get a text record for an ENS name + */ + async getText(name: string, key: string): Promise { + const resolverAddress = await this.getResolver(name); + if (!resolverAddress) { + return null; + } + + const node = this.namehash(name); + + // Encode the text() call: selector + node + encoded string key + const encodedKey = this.abiCoder.encode(["string"], [key]); + // The data format is: selector + node + offset (0x40) + string data + // For text(bytes32,string), ABI encoding requires: + // - bytes32 node (32 bytes) + // - offset to string (32 bytes pointing to 0x40 = 64) + // - string length (32 bytes) + // - string data (padded to 32 bytes) + + const data = + SELECTORS.text + + node.slice(2) + + "0000000000000000000000000000000000000000000000000000000000000040" + + encodedKey.slice(66); // Skip the 0x and first 32 bytes (offset) + + try { + const result = await this.ethCall(resolverAddress, data); + + if (result === "0x" || result.length <= 2) { + return null; + } + + return this.decodeString(result); + } catch { + return null; + } + } + + /** + * Get all common text records for an ENS name + */ + async getAllTextRecords( + name: string, + ): Promise> { + const records: Record = {}; + + // Fetch all records in parallel + const results = await Promise.all( + TEXT_RECORD_KEYS.map(async (key) => { + const value = await this.getText(name, key); + return { key, value }; + }), + ); + + for (const { key, value } of results) { + if (value) { + records[key] = value; + } + } + + return records; + } + + /** + * Get the contenthash for an ENS name + */ + async getContenthash(name: string): Promise { + const resolverAddress = await this.getResolver(name); + if (!resolverAddress) { + return null; + } + + const node = this.namehash(name); + const data = SELECTORS.contenthash + node.slice(2); + + try { + const result = await this.ethCall(resolverAddress, data); + + if (result === "0x" || result.length <= 2) { + return null; + } + + // The contenthash is returned as dynamic bytes + // Decode it and return as hex + const decoded = this.decodeBytes(result); + return decoded; + } catch { + return null; + } + } + + /** + * Get all ENS records for a name + */ + async getRecords(name: string): Promise { + const [address, contenthash, textRecords] = await Promise.all([ + this.resolve(name), + this.getContenthash(name), + this.getAllTextRecords(name), + ]); + + return { + name, + address: address || undefined, + contenthash: contenthash || undefined, + textRecords, + }; + } + + /** + * Decode an ABI-encoded string from RPC result + */ + private decodeString(data: string): string | null { + try { + // ABI-encoded string format: + // First 32 bytes: offset to string data + // At offset: 32 bytes length + string data (padded to 32 bytes) + if (data.length < 66) return null; + + // Parse the offset + const offset = parseInt(data.slice(2, 66), 16) * 2 + 2; + + // Parse the length + const lengthHex = data.slice(offset, offset + 64); + const length = parseInt(lengthHex, 16); + + if (length === 0) return null; + + // Extract the string bytes + const stringHex = data.slice(offset + 64, offset + 64 + length * 2); + + // Convert hex to string + let result = ""; + for (let i = 0; i < stringHex.length; i += 2) { + result += String.fromCharCode(parseInt(stringHex.slice(i, i + 2), 16)); + } + + return result; + } catch { + return null; + } + } + + /** + * Decode ABI-encoded bytes from RPC result + */ + private decodeBytes(data: string): string | null { + try { + if (data.length < 66) return null; + + // Parse the offset + const offset = parseInt(data.slice(2, 66), 16) * 2 + 2; + + // Parse the length + const lengthHex = data.slice(offset, offset + 64); + const length = parseInt(lengthHex, 16); + + if (length === 0) return null; + + // Extract the bytes + const bytesHex = data.slice(offset + 64, offset + 64 + length * 2); + + return "0x" + bytesHex; + } catch { + return null; + } + } + + /** + * Decode contenthash to human-readable format + * Supports IPFS, IPNS, Swarm, Onion, and Skylink + */ + decodeContenthash(contenthash: string): { type: string; url: string } | null { + if (!contenthash || contenthash === "0x") return null; + + try { + // Remove 0x prefix + const hex = contenthash.slice(2); + + // Check the codec prefix + // IPFS: e3 01 01 (ipfs-ns, dag-pb, sha2-256) + // IPNS: e5 01 01 + // Swarm: e4 01 01 + // Onion: bc (onion) + // Onion3: bd + // Skylink: 90b2c605 + + if (hex.startsWith("e3010120")) { + // IPFS CIDv0 (starts with Qm) + const cid = this.hexToBase58(hex.slice(8)); + return { type: "ipfs", url: `ipfs://${cid}` }; + } else if (hex.startsWith("e5010120")) { + // IPNS + const cid = this.hexToBase58(hex.slice(8)); + return { type: "ipns", url: `ipns://${cid}` }; + } else if (hex.startsWith("e40101")) { + // Swarm + const hash = hex.slice(6); + return { type: "swarm", url: `bzz://${hash}` }; + } else if (hex.startsWith("bc")) { + // Onion v2 + const onion = this.hexToBase32(hex.slice(2)); + return { type: "onion", url: `http://${onion}.onion` }; + } else if (hex.startsWith("bd")) { + // Onion v3 + const onion = this.hexToBase32(hex.slice(2)); + return { type: "onion", url: `http://${onion}.onion` }; + } + + return { type: "unknown", url: contenthash }; + } catch { + return null; + } + } + + /** + * Convert hex to base58 (for IPFS CIDs) + * Simplified version - for full support use a proper base58 library + */ + private hexToBase58(hex: string): string { + // This is a simplified conversion + // For production, use a proper base58 library + const ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + + let num = BigInt("0x" + hex); + let result = ""; + + const fifty8 = BigInt(58); + const zero = BigInt(0); + + while (num > zero) { + const remainder = Number(num % fifty8); + result = ALPHABET[remainder] + result; + num = num / fifty8; + } + + // Add leading zeros + for (let i = 0; i < hex.length; i += 2) { + if (hex.slice(i, i + 2) === "00") { + result = "1" + result; + } else { + break; + } + } + + return result; + } + + /** + * Convert hex to base32 (for onion addresses) + */ + private hexToBase32(hex: string): string { + const ALPHABET = "abcdefghijklmnopqrstuvwxyz234567"; + const bytes: number[] = []; + + for (let i = 0; i < hex.length; i += 2) { + bytes.push(parseInt(hex.slice(i, i + 2), 16)); + } + + let bits = ""; + for (const byte of bytes) { + bits += byte.toString(2).padStart(8, "0"); + } + + let result = ""; + for (let i = 0; i < bits.length; i += 5) { + const chunk = bits.slice(i, i + 5).padEnd(5, "0"); + result += ALPHABET[parseInt(chunk, 2)]; + } + + return result; + } + + /** + * Check if a string looks like an ENS name + */ + static isENSName(name: string): boolean { + if (!name || typeof name !== "string") return false; + + // Must contain at least one dot + if (!name.includes(".")) return false; + + // Common ENS patterns + const ensPatterns = [ + /\.eth$/i, + /\.xyz$/i, + /\.luxe$/i, + /\.kred$/i, + /\.art$/i, + /\.club$/i, + ]; + + return ensPatterns.some((pattern) => pattern.test(name)); + } +} + +export default ENSService; diff --git a/src/types/index.ts b/src/types/index.ts index bb1aa85..17a7942 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -468,3 +468,40 @@ export interface AddressTransactionsResult { isComplete: boolean; // true if we have full history (trace_filter) message?: string; // Optional message about limitations } + +// ==================== ENS TYPES ==================== + +/** + * ENS records for a name + */ +export interface ENSRecords { + name?: string; + address?: string; + contenthash?: string; + textRecords: Record; +} + +/** + * Result of ENS forward resolution + */ +export interface ENSResolveResult { + address: string; + ensName: string; + records?: ENSRecords; +} + +/** + * Result of ENS reverse resolution + */ +export interface ENSReverseResult { + ensName: string | null; + verified: boolean; // true if forward resolution matches the original address +} + +/** + * Decoded contenthash + */ +export interface DecodedContenthash { + type: string; + url: string; +} From 5d06f82031badb8e9554a5488640825e23fcf5b4 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Sat, 29 Nov 2025 20:32:43 -0300 Subject: [PATCH 002/103] Update logo URL in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29c6fe3..de3d571 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- OpenScan Logo + OpenScan Logo

# OpenScan From 85a775a04c86a41855d0b3d8081e6db2ec008723 Mon Sep 17 00:00:00 2001 From: Augusto Lemble Date: Sun, 30 Nov 2025 09:43:34 -0300 Subject: [PATCH 003/103] Update GitHub Pages URL in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de3d571..3ecaca5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A trustless, open-source, standalone web-app, multi-chain blockchain explorer for Ethereum, Layer 2 networks, and local development chains, allowing the direct interaction with verified smart contracts. **Official URL:** [https://openscan.eth.link/](https://openscan.eth.link/) -**GitHub Pages:** [https://openscan.github.io/explorer/](https://openscan.github.io/explorer/) +**GitHub Pages:** [https://openscan-explorer.github.io/explorer/](https://openscan.github.io/explorer/) ## Features From f0f23d69e4f109e42146971b643d9c5c4c39b4ab Mon Sep 17 00:00:00 2001 From: Mati OS Date: Sun, 30 Nov 2025 13:32:36 -0300 Subject: [PATCH 004/103] Update biome scripts --- biome.json | 16 +++++++++++++--- package-lock.json | 1 - package.json | 7 +++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/biome.json b/biome.json index cbaf9de..11d01ff 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,15 @@ { - "files": { - "includes": ["**", "!**/*.css"] - } + "files": { + "includes": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.json", "!**/*.css"] + }, + "linter": { + "rules": { + "recommended": true + } + }, + "formatter": { + "lineWidth": 100, + "indentStyle": "space", + "indentWidth": 2 + } } diff --git a/package-lock.json b/package-lock.json index d6933d7..3921932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1826,7 +1826,6 @@ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.7.tgz", "integrity": "sha512-CTbAS/jNAiUc6rcq94BrTB8z83O9+BsgWj2sBCQg9rD6Wkh2gjfR87usjx0Ncx0zGXP1NKgT7JNglay5Zfs9jw==", "dev": true, - "license": "MIT OR Apache-2.0", "bin": { "biome": "bin/biome" }, diff --git a/package.json b/package.json index 4d1e7bc..0212dc1 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,14 @@ "scripts": { "start": "NODE_ENV=development webpack serve --config webpack.config.js --mode development", "build": "NODE_ENV=production webpack --config webpack.config.js --mode production", - "test": "npx vitest", + "test": "npx vitest", "test:run": "npx vitest run", "dev": "bash scripts/run-test-env.sh", "typecheck": "tsc --noEmit", - "format:fix": "npx @biomejs/biome format --write" + "format": "npx @biomejs/biome format", + "format:fix": "npx @biomejs/biome format --write", + "lint": "npx @biomejs/biome lint", + "lint:fix": "npx @biomejs/biome lint --write --max-diagnostics 1024" }, "eslintConfig": { "extends": [ From 2076bc8dc5a8da2cb39a563f4f545d54bb365f56 Mon Sep 17 00:00:00 2001 From: Mati OS Date: Sun, 30 Nov 2025 13:34:03 -0300 Subject: [PATCH 005/103] Make biome happy :) --- src/App.tsx | 224 +- src/components/LazyComponents.tsx | 14 +- src/components/common/AddressDisplay.tsx | 3376 ++++++++--------- src/components/common/BlockDisplay.tsx | 913 +++-- src/components/common/ErrorBoundary.tsx | 222 +- src/components/common/Footer.tsx | 118 +- src/components/common/IsometricBlocks.tsx | 269 +- src/components/common/Loader.tsx | 40 +- src/components/common/Loading.tsx | 14 +- src/components/common/LongString.tsx | 63 +- src/components/common/Navbar.tsx | 422 +-- .../common/NetworkBlockIndicator.tsx | 275 +- src/components/common/NetworkIcon.tsx | 147 +- src/components/common/NetworkStatsDisplay.tsx | 392 +- src/components/common/NotificationDisplay.tsx | 50 +- src/components/common/RPCIndicator.tsx | 212 +- src/components/common/SearchBox.tsx | 88 +- src/components/common/TransactionDisplay.tsx | 1413 ++++--- .../common/TransactionReceiptDisplay.tsx | 118 +- src/components/common/VersionWarningIcon.tsx | 83 +- src/components/common/modal/BaseModal.tsx | 110 +- src/components/devtools/ContractsSection.tsx | 1093 +++--- .../devtools/DevelopmentSection.tsx | 67 +- src/components/devtools/SignaturesSection.tsx | 964 ++--- .../devtools/TransactionsSection.tsx | 1009 ++--- src/components/devtools/UtilsSection.tsx | 752 ++-- src/components/pages/About.tsx | 229 +- src/components/pages/Address.tsx | 295 +- src/components/pages/Block.tsx | 186 +- src/components/pages/Blocks.tsx | 446 ++- src/components/pages/Chain.tsx | 98 +- src/components/pages/DevTools.test.ts | 995 ++--- src/components/pages/DevTools.tsx | 70 +- src/components/pages/Home.tsx | 134 +- src/components/pages/Mempool.tsx | 22 +- src/components/pages/Settings.tsx | 388 +- src/components/pages/Tx.tsx | 192 +- src/components/pages/Txs.tsx | 481 ++- src/config/config.json | 94 +- src/config/events.json | 230 +- src/config/index.ts | 54 +- src/config/networks.ts | 263 +- src/config/rpcConfig.ts | 19 +- src/context/AppContext.tsx | 239 +- src/context/NotificationContext.tsx | 125 +- src/context/SettingsContext.tsx | 231 +- src/hooks/useAppReady.ts | 44 +- src/hooks/useDataService.ts | 47 +- src/hooks/useModalManager.ts | 34 +- src/hooks/useNotify.ts | 17 +- src/hooks/useProviderSelection.ts | 52 +- src/hooks/useSelectedData.ts | 54 +- src/hooks/useSourcify.ts | 338 +- src/hooks/useWagmiConnection.ts | 98 +- src/hooks/useZipJsonReader.tsx | 222 +- src/index.tsx | 26 +- src/services/DataService.ts | 1461 ++++--- src/services/EVM/Arbitrum/adapters/address.ts | 30 +- src/services/EVM/Arbitrum/adapters/block.ts | 88 +- .../EVM/Arbitrum/adapters/transaction.ts | 111 +- src/services/EVM/Arbitrum/fetchers/address.ts | 412 +- src/services/EVM/Arbitrum/fetchers/block.ts | 87 +- .../EVM/Arbitrum/fetchers/networkStats.ts | 91 +- .../EVM/Arbitrum/fetchers/transaction.ts | 59 +- src/services/EVM/L1/adapters/address.ts | 30 +- src/services/EVM/L1/adapters/block.ts | 77 +- src/services/EVM/L1/adapters/transaction.ts | 94 +- src/services/EVM/L1/fetchers/address.ts | 490 ++- src/services/EVM/L1/fetchers/block.ts | 87 +- src/services/EVM/L1/fetchers/networkStats.ts | 95 +- src/services/EVM/L1/fetchers/trace.ts | 380 +- src/services/EVM/L1/fetchers/transaction.ts | 59 +- src/services/EVM/Optimism/adapters/address.ts | 30 +- src/services/EVM/Optimism/adapters/block.ts | 79 +- .../EVM/Optimism/adapters/transaction.ts | 107 +- src/services/EVM/Optimism/fetchers/address.ts | 415 +- src/services/EVM/Optimism/fetchers/block.ts | 87 +- .../EVM/Optimism/fetchers/networkStats.ts | 91 +- .../EVM/Optimism/fetchers/transaction.ts | 59 +- src/services/EVM/common/RPCClient.ts | 665 ++-- src/services/EVM/common/TraceService.ts | 306 +- src/services/RPCMetadataService.ts | 113 +- src/services/adapters/transaction.ts | 84 +- src/types/assets.d.ts | 16 +- src/types/index.ts | 562 ++- src/utils/artifactsStorage.ts | 62 +- src/utils/devtools.ts | 567 ++- src/utils/eventDecoder.ts | 514 ++- src/utils/networkConfig.ts | 8 +- src/utils/rpcStorage.ts | 201 +- src/utils/web3Security.ts | 364 +- 91 files changed, 12624 insertions(+), 13528 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 02af886..9404d21 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,37 +1,26 @@ -import { - BrowserRouter as Router, - HashRouter, - Routes, - Route, - Navigate, -} from "react-router-dom"; +import { BrowserRouter as Router, HashRouter, Routes, Route, Navigate } from "react-router-dom"; import { useCallback } from "react"; import { WagmiProvider } from "wagmi"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -// @ts-ignore -import { - RainbowKitProvider, - darkTheme, - lightTheme, -} from "@rainbow-me/rainbowkit"; +import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit"; import { networkConfig } from "./utils/networkConfig"; import "./styles/rainbowkit.css"; // Detect if we're running on GitHub Pages and get the correct basename function getBasename(): string { - const { hostname, pathname } = window.location; + const { hostname, pathname } = window.location; - // Check if we're on GitHub Pages - if (hostname.includes("github.io")) { - // Extract repo name from pathname (first segment after domain) - const pathSegments = pathname.split("/").filter(Boolean); - if (pathSegments.length > 0) { - return `/${pathSegments[0]}`; - } - } + // Check if we're on GitHub Pages + if (hostname.includes("github.io")) { + // Extract repo name from pathname (first segment after domain) + const pathSegments = pathname.split("/").filter(Boolean); + if (pathSegments.length > 0) { + return `/${pathSegments[0]}`; + } + } - // For local development or custom domains, no basename needed - return ""; + // For local development or custom domains, no basename needed + return ""; } import Navbar from "./components/common/Navbar"; import Footer from "./components/common/Footer"; @@ -46,129 +35,116 @@ import "./styles/forms.css"; import { useAppReady, useOnAppReady } from "./hooks/useAppReady"; import Loading from "./components/common/Loading"; import { - LazyHome, - LazyChain, - LazyBlocks, - LazyBlock, - LazyTxs, - LazyTx, - LazyAddress, - LazyMempool, - LazySettings, - LazyDevTools, - LazyAbout, + LazyHome, + LazyChain, + LazyBlocks, + LazyBlock, + LazyTxs, + LazyTx, + LazyAddress, + LazyMempool, + LazySettings, + LazyDevTools, + LazyAbout, } from "./components/LazyComponents"; import { NotificationProvider } from "./context/NotificationContext"; -import { - SettingsProvider, - useTheme, - useSettings, -} from "./context/SettingsContext"; +import { SettingsProvider, useTheme, useSettings } from "./context/SettingsContext"; // Detect GH Pages once -const isGhPages = - typeof window !== "undefined" && - window.location.hostname.includes("github.io"); +const isGhPages = typeof window !== "undefined" && window.location.hostname.includes("github.io"); // Create a client for React Query const queryClient = new QueryClient(); // Separate component that uses the theme context function AppContent() { - const onAppReadyCallback = useCallback(async () => {}, []); + const onAppReadyCallback = useCallback(async () => {}, []); - useOnAppReady(onAppReadyCallback); + useOnAppReady(onAppReadyCallback); - const { fullyReady } = useAppReady(); - const { isDarkMode } = useTheme(); // Now this is inside ThemeProvider - const { settings } = useSettings(); + const { fullyReady } = useAppReady(); + const { isDarkMode } = useTheme(); // Now this is inside ThemeProvider + const { settings } = useSettings(); - return ( - <> - {!fullyReady ? ( - - ) : ( - <> - {/* Background animated blocks - full screen (conditionally rendered) */} - {settings.showBackgroundBlocks && ( -
- -
- )} + return ( + <> + {!fullyReady ? ( + + ) : ( + <> + {/* Background animated blocks - full screen (conditionally rendered) */} + {settings.showBackgroundBlocks && ( +
+ +
+ )} -
- - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } - /> - } /> - } /> - } /> - -
-
- - )} - - ); +
+ + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+
+ + )} + + ); } // Main App component that provides the theme context function App() { - const BaseRouter = isGhPages ? HashRouter : Router; - // IMPORTANT: no basename for HashRouter - const basename = isGhPages ? "" : getBasename(); + const BaseRouter = isGhPages ? HashRouter : Router; + // IMPORTANT: no basename for HashRouter + const basename = isGhPages ? "" : getBasename(); - return ( - - - - - - - - - - - - - - - - ); + return ( + + + + + + + + + + + + + + + + ); } // Wrapper component to use theme inside SettingsProvider -function RainbowKitProviderWrapper({ - children, -}: { - children: React.ReactNode; -}) { - const { isDarkMode } = useTheme(); +function RainbowKitProviderWrapper({ children }: { children: React.ReactNode }) { + const { isDarkMode } = useTheme(); - return ( - - {children} - - ); + return ( + + {children} + + ); } export default App; diff --git a/src/components/LazyComponents.tsx b/src/components/LazyComponents.tsx index 1f00f29..4c80a69 100644 --- a/src/components/LazyComponents.tsx +++ b/src/components/LazyComponents.tsx @@ -16,13 +16,13 @@ const About = lazy(() => import("./pages/About")); // Higher-order component to wrap lazy components with Suspense export const withSuspense = (Component: React.ComponentType) => { - return function SuspenseWrapper(props: any) { - return ( - }> - - - ); - }; + return function SuspenseWrapper(props: any) { + return ( + }> + + + ); + }; }; // Export lazy components wrapped with Suspense diff --git a/src/components/common/AddressDisplay.tsx b/src/components/common/AddressDisplay.tsx index bf1e503..d8a9898 100644 --- a/src/components/common/AddressDisplay.tsx +++ b/src/components/common/AddressDisplay.tsx @@ -1,1797 +1,1611 @@ import React, { useContext, useState, useMemo, useCallback } from "react"; import { Link } from "react-router-dom"; import { useSourcify } from "../../hooks/useSourcify"; -import type { - Address, - AddressTransactionsResult, - Transaction, - RPCMetadata, -} from "../../types"; +import type { Address, AddressTransactionsResult, Transaction, RPCMetadata } from "../../types"; import { AppContext } from "../../context"; -import { - useWriteContract, - useWaitForTransactionReceipt, -} from "wagmi"; +import { useWriteContract, useWaitForTransactionReceipt } from "wagmi"; import { parseEther, encodeFunctionData } from "viem"; import { RPCIndicator } from "./RPCIndicator"; import { ConnectButton } from "@rainbow-me/rainbowkit"; interface AddressDisplayProps { - address: Address; - addressHash: string; - chainId?: string; - transactionsResult?: AddressTransactionsResult | null; - transactionDetails?: Transaction[]; - loadingTxDetails?: boolean; - metadata?: RPCMetadata; - selectedProvider?: string | null; - onProviderSelect?: (provider: string) => void; + address: Address; + addressHash: string; + chainId?: string; + transactionsResult?: AddressTransactionsResult | null; + transactionDetails?: Transaction[]; + loadingTxDetails?: boolean; + metadata?: RPCMetadata; + selectedProvider?: string | null; + onProviderSelect?: (provider: string) => void; } const AddressDisplay: React.FC = React.memo( - ({ - address, - addressHash, - chainId = "1", - transactionsResult, - transactionDetails = [], - loadingTxDetails = false, - metadata, - selectedProvider, - onProviderSelect, - }) => { - const [storageSlot, setStorageSlot] = useState(""); - const [storageValue, setStorageValue] = useState(""); - const [showContractDetails, setShowContractDetails] = useState(false); - const [selectedWriteFunction, setSelectedWriteFunction] = - useState(null); - const [selectedReadFunction, setSelectedReadFunction] = useState(null); - const [functionInputs, setFunctionInputs] = useState< - Record - >({}); - const [readFunctionResult, setReadFunctionResult] = useState(null); - const [isReadingFunction, setIsReadingFunction] = useState(false); - const { jsonFiles, rpcUrls } = useContext(AppContext); - - // Wagmi hooks for contract interaction - const { - data: hash, - writeContract, - isPending, - isError, - error, - } = useWriteContract(); - const { isLoading: isConfirming, isSuccess: isConfirmed } = - useWaitForTransactionReceipt({ hash }); - - const isContract = useMemo( - () => address.code && address.code !== "0x", - [address.code], - ); - - // Fetch Sourcify data only if it's a contract - const { - data: sourcifyData, - loading: sourcifyLoading, - isVerified, - } = useSourcify( - Number(chainId), - isContract ? addressHash : undefined, - true, - ); - - // Memoized helper functions - const truncate = useCallback((str: string, start = 6, end = 4) => { - if (!str) return ""; - if (str.length <= start + end) return str; - return `${str.slice(0, start)}...${str.slice(-end)}`; - }, []); - - const formatBalance = useCallback((balance: string) => { - try { - const eth = Number(balance) / 1e18; - return `${eth.toFixed(6)} ETH`; - } catch (e) { - return balance; - } - }, []); - - const formatValue = useCallback((value: string) => { - try { - const eth = Number(value) / 1e18; - return `${eth.toFixed(6)} ETH`; - } catch (e) { - return "0 ETH"; - } - }, []); - - // Memoized formatted balance - const formattedBalance = useMemo( - () => formatBalance(address.balance), - [address.balance, formatBalance], - ); - - const handleGetStorage = useCallback(() => { - // Check if the slot exists in the storeageAt object - if (address.storeageAt?.[storageSlot]) { - setStorageValue(address.storeageAt[storageSlot]); - } else { - setStorageValue( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ); - } - }, [address.storeageAt, storageSlot]); - - // Check if we have local artifact data for this address - const localArtifact = jsonFiles[addressHash.toLowerCase()]; - - // Parse local artifact to sourcify format if it exists - memoized - const parsedLocalData = useMemo(() => { - if (!localArtifact) return null; - return { - name: localArtifact.contractName, - compilerVersion: localArtifact.buildInfo?.solcLongVersion, - evmVersion: localArtifact.buildInfo?.input?.settings?.evmVersion, - abi: localArtifact.abi, - files: localArtifact.sourceCode - ? [ - { - name: localArtifact.sourceName || "Contract.sol", - path: localArtifact.sourceName || "Contract.sol", - content: localArtifact.sourceCode, - }, - ] - : undefined, - metadata: { - language: localArtifact.buildInfo?.input?.language, - compiler: localArtifact.buildInfo - ? { - version: localArtifact.buildInfo.solcVersion, - } - : undefined, - }, - match: "perfect" as const, - creation_match: null, - runtime_match: null, - chainId: chainId, - address: addressHash, - verifiedAt: undefined, - }; - }, [localArtifact, chainId, addressHash]); - - // Use local artifact data if available and sourcify is not verified, otherwise use sourcify - const contractData = useMemo( - () => (isVerified && sourcifyData ? sourcifyData : parsedLocalData), - [isVerified, sourcifyData, parsedLocalData], - ); - - const handleWriteFunction = useCallback(async () => { - if (!selectedWriteFunction) return; - - try { - // Prepare function arguments - const args: any[] = []; - if ( - selectedWriteFunction.inputs && - selectedWriteFunction.inputs.length > 0 - ) { - for (const input of selectedWriteFunction.inputs) { - const paramName = - input.name || - `param${selectedWriteFunction.inputs.indexOf(input)}`; - const value = functionInputs[paramName]; - - if (!value && value !== "0") { - alert(`Please provide value for ${paramName}`); - return; - } - - args.push(value); - } - } - - // Prepare transaction value for payable functions - let txValue: bigint | undefined; - if ( - selectedWriteFunction.stateMutability === "payable" && - functionInputs["_value"] - ) { - try { - txValue = parseEther(functionInputs["_value"]); - } catch (e) { - alert("Invalid ETH value"); - return; - } - } - - // Call the contract - writeContract({ - address: addressHash as `0x${string}`, - abi: contractData?.abi || [], - functionName: selectedWriteFunction.name, - args: args, - value: txValue, - }); - } catch (err) { - console.error("Error writing to contract:", err); - alert(`Error: ${err instanceof Error ? err.message : "Unknown error"}`); - } - }, [ - selectedWriteFunction, - functionInputs, - addressHash, - contractData?.abi, - writeContract, - ]); - - const handleReadFunction = useCallback(async () => { - if (!selectedReadFunction || !contractData) return; - - setIsReadingFunction(true); - setReadFunctionResult(null); - - try { - // Get RPC URL for the current chain - const chainIdNum = Number(chainId); - const rpcUrlsForChain = rpcUrls[chainIdNum as keyof typeof rpcUrls]; - - if (!rpcUrlsForChain) { - throw new Error(`No RPC URL configured for chain ${chainId}`); - } - - // Get first RPC URL (could be string or array) - const rpcUrl = Array.isArray(rpcUrlsForChain) - ? rpcUrlsForChain[0] - : rpcUrlsForChain; - - if (!rpcUrl) { - // Defensive: ensure rpcUrl is defined before calling fetch - throw new Error(`No RPC URL configured for chain ${chainId}`); - } - - // Prepare function arguments - const args: any[] = []; - if ( - selectedReadFunction.inputs && - selectedReadFunction.inputs.length > 0 - ) { - for (const input of selectedReadFunction.inputs) { - const paramName = - input.name || - `param${selectedReadFunction.inputs.indexOf(input)}`; - const value = functionInputs[paramName]; - - if (!value && value !== "0") { - alert(`Please provide value for ${paramName}`); - setIsReadingFunction(false); - return; - } - - args.push(value); - } - } - - // Use fetch to call the RPC directly for read functions - const response = await fetch(rpcUrl, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - jsonrpc: "2.0", - method: "eth_call", - params: [ - { - to: addressHash, - data: encodeFunctionData({ - abi: contractData.abi, - functionName: selectedReadFunction.name, - args: args, - }), - }, - "latest", - ], - id: 1, - }), - }); - - const data = await response.json(); - - if (data.error) { - throw new Error(data.error.message || "Contract call failed"); - } - - setReadFunctionResult(data.result); - } catch (err) { - console.error("Error reading from contract:", err); - setReadFunctionResult( - `Error: ${err instanceof Error ? err.message : "Unknown error"}`, - ); - } finally { - setIsReadingFunction(false); - } - }, [ - selectedReadFunction, - contractData, - chainId, - functionInputs, - addressHash, - ]); - - return ( -
-
-
- Address - {addressHash} -
- {metadata && selectedProvider !== undefined && onProviderSelect && ( - - )} -
- -
- {/* Address Details Section */} -
-
- Address Details -
- - {/* Type */} -
- Type: - - {isContract ? ( - - πŸ“„ Contract - - ) : ( - - πŸ‘€ Externally Owned Account (EOA) - - )} - -
- - {/* Balance */} -
- Balance: - - - {formatBalance(address.balance)} - - -
- - {/* Transaction Count (Nonce) */} -
- Transactions: - - {Number(address.txCount).toLocaleString()} txns - -
- - {/* Verification Status (only for contracts) */} - {isContract && ( - <> -
- Contract Verified: - - {sourcifyLoading ? ( - - Checking Sourcify... - - ) : isVerified || parsedLocalData ? ( - - βœ“ Verified - {contractData?.match && ( - - {contractData.match === "perfect" - ? parsedLocalData - ? "Local JSON" - : "Perfect Match" - : "Partial Match"} - - )} - - ) : ( - - Not Verified - - )} - -
- - )} - - {/* Contract Name (if verified) */} - {isContract && contractData?.name && ( -
- Contract Name: - {contractData.name} -
- )} - - {/* Compiler Version (if verified) */} - {isContract && contractData?.compilerVersion && ( -
- Compiler: - - {contractData.compilerVersion} - -
- )} -
- - {/* Contract Verification Details */} - {isContract && (isVerified || parsedLocalData) && contractData && ( -
-
setShowContractDetails(!showContractDetails)} - > - Contract Details - - {showContractDetails ? " β–Ό" : " β–Ά"} - -
- - {showContractDetails && ( - <> - {contractData.name && ( -
- Contract Name - - {contractData.name} - -
- )} - - {contractData.compilerVersion && ( -
- Compiler Version - - {contractData.compilerVersion} - -
- )} - - {contractData.evmVersion && ( -
- EVM Version - - {contractData.evmVersion} - -
- )} - - {contractData.chainId && ( -
- Chain ID - {contractData.chainId} -
- )} - - {contractData.verifiedAt && ( -
- Verified At - - {new Date(contractData.verifiedAt).toLocaleString()} - -
- )} - - {contractData.match && ( -
- Match Type - - {contractData.match.toUpperCase()} - -
- )} - - {contractData.metadata?.compiler && ( -
- Compiler - - {contractData.metadata.compiler.version} - -
- )} - - {contractData.creation_match && ( -
- Creation Match - - {contractData.creation_match.toUpperCase()} - -
- )} - - {contractData.runtime_match && ( -
- Runtime Match - - {contractData.runtime_match.toUpperCase()} - -
- )} - - {/* Contract Bytecode */} -
-
{ - const elem = - document.getElementById("bytecode-content"); - const icon = document.getElementById("bytecode-icon"); - if (elem && icon) { - const isHidden = elem.style.display === "none"; - elem.style.display = isHidden ? "block" : "none"; - icon.textContent = isHidden ? "β–Ό" : "β–Ά"; - } - }} - > - Contract Bytecode - - β–Ά - -
-
- {address.code} -
-
- - {/* Source Code */} - {((contractData.files && contractData.files.length > 0) || - (contractData as any).sources) && - (() => { - // Prepare source files array - either from files or sources object - const sources = (contractData as any).sources; - const sourceFiles = - contractData.files && contractData.files.length > 0 - ? contractData.files - : sources - ? Object.entries(sources).map( - ([path, source]: [string, any]) => ({ - name: path, - path: path, - content: source.content || "", - }), - ) - : []; - - return sourceFiles.length > 0 ? ( -
-
{ - const elem = document.getElementById( - "source-code-content", - ); - const icon = - document.getElementById("source-code-icon"); - if (elem && icon) { - const isHidden = elem.style.display === "none"; - elem.style.display = isHidden - ? "block" - : "none"; - icon.textContent = isHidden ? "β–Ό" : "β–Ά"; - } - }} - > - Source Code - - β–Ά - -
-
- {sourceFiles.map((file: any, idx: number) => ( -
-
- πŸ“„ {file.name || file.path} -
-
-																	{file.content}
-																
-
- ))} -
-
- ) : null; - })()} - - {/* Raw ABI */} - {contractData.abi && contractData.abi.length > 0 && ( -
-
{ - const elem = - document.getElementById("raw-abi-content"); - const icon = document.getElementById("raw-abi-icon"); - if (elem && icon) { - const isHidden = elem.style.display === "none"; - elem.style.display = isHidden ? "block" : "none"; - icon.textContent = isHidden ? "β–Ό" : "β–Ά"; - } - }} - > - Raw ABI - - β–Ά - -
-
- {JSON.stringify(contractData.abi, null, 2)} -
-
- )} - - {/* Contract ABI */} - {contractData.abi && contractData.abi.length > 0 && ( -
-
- Functions - - {({ - account, - chain, - openAccountModal, - openChainModal, - openConnectModal, - authenticationStatus, - mounted, - }: any) => { - const ready = - mounted && authenticationStatus !== "loading"; - const connected = - ready && - account && - chain && - (!authenticationStatus || - authenticationStatus === "authenticated"); - - return ( -
- {(() => { - if (!connected) { - return ( - - ); - } - - if (chain.unsupported) { - return ( - - ); - } - - return ( -
- - -
- ); - })()} -
- ); - }} -
-
-
- {/* Read Functions (view/pure) */} - {(() => { - const readFunctions = contractData.abi.filter( - (item: any) => - item.type === "function" && - (item.stateMutability === "view" || - item.stateMutability === "pure"), - ); - return ( - readFunctions.length > 0 && ( -
-
- Read Functions ({readFunctions.length}) -
-
- {readFunctions.map( - (func: any, idx: number) => ( - - ), - )} -
-
- ) - ); - })()} - - {/* Write Functions (payable/nonpayable) */} - {(() => { - const writeFunctions = contractData.abi.filter( - (item: any) => - item.type === "function" && - (item.stateMutability === "payable" || - item.stateMutability === "nonpayable" || - !item.stateMutability), - ); - return ( - writeFunctions.length > 0 && ( -
-
- Write Functions ({writeFunctions.length}) -
-
- {writeFunctions.map( - (func: any, idx: number) => ( - - ), - )} -
-
- ) - ); - })()} - - {/* Events */} - {contractData.abi.filter( - (item: any) => item.type === "event", - ).length > 0 && ( -
-
- Events ( - { - contractData.abi.filter( - (item: any) => item.type === "event", - ).length - } - ) -
-
- {contractData.abi - .filter((item: any) => item.type === "event") - .slice(0, 10) - .map((event: any, idx: number) => ( - - {event.name} - - ))} - {contractData.abi.filter( - (item: any) => item.type === "event", - ).length > 10 && ( - - + - {contractData.abi.filter( - (item: any) => item.type === "event", - ).length - 10}{" "} - more - - )} -
-
- )} - - {/* Read Function Form */} - {selectedReadFunction && ( -
-
- {selectedReadFunction.name} -
- - {selectedReadFunction.inputs && - selectedReadFunction.inputs.length > 0 ? ( -
- {selectedReadFunction.inputs.map( - (input: any, idx: number) => ( -
- - - setFunctionInputs({ - ...functionInputs, - [input.name || `param${idx}`]: - e.target.value, - }) - } - placeholder={`Enter ${input.type}`} - style={{ - width: "100%", - padding: "8px 12px", - background: "rgba(0, 0, 0, 0.3)", - border: - "1px solid rgba(59, 130, 246, 0.3)", - borderRadius: "6px", - color: "#fff", - fontSize: "0.85rem", - fontFamily: "monospace", - }} - /> -
- ), - )} -
- ) : ( -
- No parameters required -
- )} - - {/* Read Result */} - {readFunctionResult !== null && ( -
-
- {readFunctionResult?.startsWith("Error") - ? "❌ Error" - : "βœ… Result"} -
- {readFunctionResult} -
- )} - -
- - -
-
- )} - - {/* Write Function Form */} - {selectedWriteFunction && ( -
-
- {selectedWriteFunction.name} - {selectedWriteFunction.stateMutability === - "payable" && ( - - payable - - )} -
- - {selectedWriteFunction.inputs && - selectedWriteFunction.inputs.length > 0 ? ( -
- {selectedWriteFunction.inputs.map( - (input: any, idx: number) => ( -
- - - setFunctionInputs({ - ...functionInputs, - [input.name || `param${idx}`]: - e.target.value, - }) - } - placeholder={`Enter ${input.type}`} - style={{ - width: "100%", - padding: "8px 12px", - background: "rgba(0, 0, 0, 0.3)", - border: - "1px solid rgba(245, 158, 11, 0.3)", - borderRadius: "6px", - color: "#fff", - fontSize: "0.85rem", - fontFamily: "monospace", - }} - /> -
- ), - )} -
- ) : ( -
- No parameters required -
- )} - - {selectedWriteFunction.stateMutability === - "payable" && ( -
- - - setFunctionInputs({ - ...functionInputs, - _value: e.target.value, - }) - } - placeholder="0.0" - style={{ - width: "100%", - padding: "8px 12px", - background: "rgba(0, 0, 0, 0.3)", - border: "1px solid rgba(16, 185, 129, 0.3)", - borderRadius: "6px", - color: "#fff", - fontSize: "0.85rem", - fontFamily: "monospace", - }} - /> -
- )} - - {/* Transaction Status */} - {(isPending || - isConfirming || - isConfirmed || - isError) && ( -
- {isPending && - "⏳ Waiting for wallet confirmation..."} - {isConfirming && - "⏳ Waiting for transaction confirmation..."} - {isConfirmed && ( -
- βœ… Transaction confirmed! - {hash && ( -
- - View transaction - -
- )} -
- )} - {isError && ( -
- ❌ Error:{" "} - {error?.message || "Transaction failed"} -
- )} -
- )} - -
- - -
-
- )} -
-
- )} - - {sourcifyData && ( - - )} - - )} -
- )} - - {/* Last Transactions Section */} -
-
- Last Transactions - {transactionsResult && ( - - {transactionsResult.source === "trace_filter" && ( - <> - ● - Complete history ({transactionDetails.length}{" "} - transactions) - - )} - {transactionsResult.source === "logs" && ( - <> - ● - Partial (logs only) - {transactionDetails.length}{" "} - transactions - - )} - {transactionsResult.source === "none" && ( - <> - ● - No data available - - )} - - )} -
- - {/* Warning message for partial data */} - {transactionsResult?.message && ( -
- - {transactionsResult.source === "none" ? "⚠️" : "ℹ️"} - - {transactionsResult.message} -
- )} - - {/* Loading state */} - {loadingTxDetails && ( -
- Loading transaction details... -
- )} - - {/* Transaction table */} - {!loadingTxDetails && transactionDetails.length > 0 && ( -
- - - - - - - - - - - - {transactionDetails.map((tx) => ( - - - - - - - - ))} - -
TX HashFromToValueStatus
- - {truncate(tx.hash, 8, 6)} - - - - {tx.from?.toLowerCase() === - addressHash.toLowerCase() - ? "This Address" - : truncate(tx.from || "", 6, 4)} - - - {tx.to ? ( - - {tx.to?.toLowerCase() === - addressHash.toLowerCase() - ? "This Address" - : truncate(tx.to, 6, 4)} - - ) : ( - - Contract Creation - - )} - - - {formatValue(tx.value)} - - - {tx.receipt?.status === "0x1" ? ( - - βœ“ Success - - ) : tx.receipt?.status === "0x0" ? ( - - βœ— Failed - - ) : ( - - ⏳ Pending - - )} -
-
- )} - - {/* Empty state */} - {!loadingTxDetails && - transactionDetails.length === 0 && - !transactionsResult?.message && ( -
- No transactions found for this address -
- )} -
- - {/* Storage Section (for contracts) */} - {isContract && ( -
-
- Contract Storage -
-
-
- Storage Slot: - -
- setStorageSlot(e.target.value)} - className="storage-input" - /> - -
-
-
- {storageValue && ( -
- Value: - -
- {storageValue} -
-
-
- )} -
-
- )} -
-
- ); - }, + ({ + address, + addressHash, + chainId = "1", + transactionsResult, + transactionDetails = [], + loadingTxDetails = false, + metadata, + selectedProvider, + onProviderSelect, + }) => { + const [storageSlot, setStorageSlot] = useState(""); + const [storageValue, setStorageValue] = useState(""); + const [showContractDetails, setShowContractDetails] = useState(false); + const [selectedWriteFunction, setSelectedWriteFunction] = useState(null); + const [selectedReadFunction, setSelectedReadFunction] = useState(null); + const [functionInputs, setFunctionInputs] = useState>({}); + const [readFunctionResult, setReadFunctionResult] = useState(null); + const [isReadingFunction, setIsReadingFunction] = useState(false); + const { jsonFiles, rpcUrls } = useContext(AppContext); + + // Wagmi hooks for contract interaction + const { data: hash, writeContract, isPending, isError, error } = useWriteContract(); + const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ + hash, + }); + + const isContract = useMemo(() => address.code && address.code !== "0x", [address.code]); + + // Fetch Sourcify data only if it's a contract + const { + data: sourcifyData, + loading: sourcifyLoading, + isVerified, + } = useSourcify(Number(chainId), isContract ? addressHash : undefined, true); + + // Memoized helper functions + const truncate = useCallback((str: string, start = 6, end = 4) => { + if (!str) return ""; + if (str.length <= start + end) return str; + return `${str.slice(0, start)}...${str.slice(-end)}`; + }, []); + + const formatBalance = useCallback((balance: string) => { + try { + const eth = Number(balance) / 1e18; + return `${eth.toFixed(6)} ETH`; + } catch (e) { + return balance; + } + }, []); + + const formatValue = useCallback((value: string) => { + try { + const eth = Number(value) / 1e18; + return `${eth.toFixed(6)} ETH`; + } catch (e) { + return "0 ETH"; + } + }, []); + + // Memoized formatted balance + const formattedBalance = useMemo( + () => formatBalance(address.balance), + [address.balance, formatBalance], + ); + + const handleGetStorage = useCallback(() => { + // Check if the slot exists in the storeageAt object + if (address.storeageAt?.[storageSlot]) { + setStorageValue(address.storeageAt[storageSlot]); + } else { + setStorageValue("0x0000000000000000000000000000000000000000000000000000000000000000"); + } + }, [address.storeageAt, storageSlot]); + + // Check if we have local artifact data for this address + const localArtifact = jsonFiles[addressHash.toLowerCase()]; + + // Parse local artifact to sourcify format if it exists - memoized + const parsedLocalData = useMemo(() => { + if (!localArtifact) return null; + return { + name: localArtifact.contractName, + compilerVersion: localArtifact.buildInfo?.solcLongVersion, + evmVersion: localArtifact.buildInfo?.input?.settings?.evmVersion, + abi: localArtifact.abi, + files: localArtifact.sourceCode + ? [ + { + name: localArtifact.sourceName || "Contract.sol", + path: localArtifact.sourceName || "Contract.sol", + content: localArtifact.sourceCode, + }, + ] + : undefined, + metadata: { + language: localArtifact.buildInfo?.input?.language, + compiler: localArtifact.buildInfo + ? { + version: localArtifact.buildInfo.solcVersion, + } + : undefined, + }, + match: "perfect" as const, + creation_match: null, + runtime_match: null, + chainId: chainId, + address: addressHash, + verifiedAt: undefined, + }; + }, [localArtifact, chainId, addressHash]); + + // Use local artifact data if available and sourcify is not verified, otherwise use sourcify + const contractData = useMemo( + () => (isVerified && sourcifyData ? sourcifyData : parsedLocalData), + [isVerified, sourcifyData, parsedLocalData], + ); + + const handleWriteFunction = useCallback(async () => { + if (!selectedWriteFunction) return; + + try { + // Prepare function arguments + const args: any[] = []; + if (selectedWriteFunction.inputs && selectedWriteFunction.inputs.length > 0) { + for (const input of selectedWriteFunction.inputs) { + const paramName = input.name || `param${selectedWriteFunction.inputs.indexOf(input)}`; + const value = functionInputs[paramName]; + + if (!value && value !== "0") { + alert(`Please provide value for ${paramName}`); + return; + } + + args.push(value); + } + } + + // Prepare transaction value for payable functions + let txValue: bigint | undefined; + if (selectedWriteFunction.stateMutability === "payable" && functionInputs["_value"]) { + try { + txValue = parseEther(functionInputs["_value"]); + } catch (e) { + alert("Invalid ETH value"); + return; + } + } + + // Call the contract + writeContract({ + address: addressHash as `0x${string}`, + abi: contractData?.abi || [], + functionName: selectedWriteFunction.name, + args: args, + value: txValue, + }); + } catch (err) { + console.error("Error writing to contract:", err); + alert(`Error: ${err instanceof Error ? err.message : "Unknown error"}`); + } + }, [selectedWriteFunction, functionInputs, addressHash, contractData?.abi, writeContract]); + + const handleReadFunction = useCallback(async () => { + if (!selectedReadFunction || !contractData) return; + + setIsReadingFunction(true); + setReadFunctionResult(null); + + try { + // Get RPC URL for the current chain + const chainIdNum = Number(chainId); + const rpcUrlsForChain = rpcUrls[chainIdNum as keyof typeof rpcUrls]; + + if (!rpcUrlsForChain) { + throw new Error(`No RPC URL configured for chain ${chainId}`); + } + + // Get first RPC URL (could be string or array) + const rpcUrl = Array.isArray(rpcUrlsForChain) ? rpcUrlsForChain[0] : rpcUrlsForChain; + + if (!rpcUrl) { + // Defensive: ensure rpcUrl is defined before calling fetch + throw new Error(`No RPC URL configured for chain ${chainId}`); + } + + // Prepare function arguments + const args: any[] = []; + if (selectedReadFunction.inputs && selectedReadFunction.inputs.length > 0) { + for (const input of selectedReadFunction.inputs) { + const paramName = input.name || `param${selectedReadFunction.inputs.indexOf(input)}`; + const value = functionInputs[paramName]; + + if (!value && value !== "0") { + alert(`Please provide value for ${paramName}`); + setIsReadingFunction(false); + return; + } + + args.push(value); + } + } + + // Use fetch to call the RPC directly for read functions + const response = await fetch(rpcUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + method: "eth_call", + params: [ + { + to: addressHash, + data: encodeFunctionData({ + abi: contractData.abi, + functionName: selectedReadFunction.name, + args: args, + }), + }, + "latest", + ], + id: 1, + }), + }); + + const data = await response.json(); + + if (data.error) { + throw new Error(data.error.message || "Contract call failed"); + } + + setReadFunctionResult(data.result); + } catch (err) { + console.error("Error reading from contract:", err); + setReadFunctionResult(`Error: ${err instanceof Error ? err.message : "Unknown error"}`); + } finally { + setIsReadingFunction(false); + } + }, [selectedReadFunction, contractData, chainId, functionInputs, addressHash, rpcUrls]); + + return ( +
+
+
+ Address + {addressHash} +
+ {metadata && selectedProvider !== undefined && onProviderSelect && ( + + )} +
+ +
+ {/* Address Details Section */} +
+
+ Address Details +
+ + {/* Type */} +
+ Type: + + {isContract ? ( + πŸ“„ Contract + ) : ( + πŸ‘€ Externally Owned Account (EOA) + )} + +
+ + {/* Balance */} +
+ Balance: + + {formatBalance(address.balance)} + +
+ + {/* Transaction Count (Nonce) */} +
+ Transactions: + {Number(address.txCount).toLocaleString()} txns +
+ + {/* Verification Status (only for contracts) */} + {isContract && ( + <> +
+ Contract Verified: + + {sourcifyLoading ? ( + Checking Sourcify... + ) : isVerified || parsedLocalData ? ( + + βœ“ Verified + {contractData?.match && ( + + {contractData.match === "perfect" + ? parsedLocalData + ? "Local JSON" + : "Perfect Match" + : "Partial Match"} + + )} + + ) : ( + Not Verified + )} + +
+ + )} + + {/* Contract Name (if verified) */} + {isContract && contractData?.name && ( +
+ Contract Name: + {contractData.name} +
+ )} + + {/* Compiler Version (if verified) */} + {isContract && contractData?.compilerVersion && ( +
+ Compiler: + {contractData.compilerVersion} +
+ )} +
+ + {/* Contract Verification Details */} + {isContract && (isVerified || parsedLocalData) && contractData && ( +
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
setShowContractDetails(!showContractDetails)} + > + Contract Details + {showContractDetails ? " β–Ό" : " β–Ά"} +
+ + {showContractDetails && ( + <> + {contractData.name && ( +
+ Contract Name + {contractData.name} +
+ )} + + {contractData.compilerVersion && ( +
+ Compiler Version + {contractData.compilerVersion} +
+ )} + + {contractData.evmVersion && ( +
+ EVM Version + {contractData.evmVersion} +
+ )} + + {contractData.chainId && ( +
+ Chain ID + {contractData.chainId} +
+ )} + + {contractData.verifiedAt && ( +
+ Verified At + + {new Date(contractData.verifiedAt).toLocaleString()} + +
+ )} + + {contractData.match && ( +
+ Match Type + + {contractData.match.toUpperCase()} + +
+ )} + + {contractData.metadata?.compiler && ( +
+ Compiler + + {contractData.metadata.compiler.version} + +
+ )} + + {contractData.creation_match && ( +
+ Creation Match + + {contractData.creation_match.toUpperCase()} + +
+ )} + + {contractData.runtime_match && ( +
+ Runtime Match + + {contractData.runtime_match.toUpperCase()} + +
+ )} + + {/* Contract Bytecode */} +
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
{ + const elem = document.getElementById("bytecode-content"); + const icon = document.getElementById("bytecode-icon"); + if (elem && icon) { + const isHidden = elem.style.display === "none"; + elem.style.display = isHidden ? "block" : "none"; + icon.textContent = isHidden ? "β–Ό" : "β–Ά"; + } + }} + > + Contract Bytecode + + β–Ά + +
+
+ {address.code} +
+
+ + {/* Source Code */} + {((contractData.files && contractData.files.length > 0) || + (contractData as any).sources) && + (() => { + // Prepare source files array - either from files or sources object + const sources = (contractData as any).sources; + const sourceFiles = + contractData.files && contractData.files.length > 0 + ? contractData.files + : sources + ? Object.entries(sources).map(([path, source]: [string, any]) => ({ + name: path, + path: path, + content: source.content || "", + })) + : []; + + return sourceFiles.length > 0 ? ( +
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
{ + const elem = document.getElementById("source-code-content"); + const icon = document.getElementById("source-code-icon"); + if (elem && icon) { + const isHidden = elem.style.display === "none"; + elem.style.display = isHidden ? "block" : "none"; + icon.textContent = isHidden ? "β–Ό" : "β–Ά"; + } + }} + > + Source Code + + β–Ά + +
+
+ {sourceFiles.map((file: any, idx: number) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+
+ πŸ“„ {file.name || file.path} +
+
{file.content}
+
+ ))} +
+
+ ) : null; + })()} + + {/* Raw ABI */} + {contractData.abi && contractData.abi.length > 0 && ( +
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
{ + const elem = document.getElementById("raw-abi-content"); + const icon = document.getElementById("raw-abi-icon"); + if (elem && icon) { + const isHidden = elem.style.display === "none"; + elem.style.display = isHidden ? "block" : "none"; + icon.textContent = isHidden ? "β–Ό" : "β–Ά"; + } + }} + > + Raw ABI + + β–Ά + +
+
+ {JSON.stringify(contractData.abi, null, 2)} +
+
+ )} + + {/* Contract ABI */} + {contractData.abi && contractData.abi.length > 0 && ( +
+
+ Functions + + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + authenticationStatus, + mounted, + }: any) => { + const ready = mounted && authenticationStatus !== "loading"; + const connected = + ready && + account && + chain && + (!authenticationStatus || authenticationStatus === "authenticated"); + + return ( +
+ {(() => { + if (!connected) { + return ( + + ); + } + + if (chain.unsupported) { + return ( + + ); + } + + return ( +
+ + +
+ ); + })()} +
+ ); + }} +
+
+
+ {/* Read Functions (view/pure) */} + {(() => { + const readFunctions = contractData.abi.filter( + (item: any) => + item.type === "function" && + (item.stateMutability === "view" || item.stateMutability === "pure"), + ); + return ( + readFunctions.length > 0 && ( +
+
+ Read Functions ({readFunctions.length}) +
+
+ {readFunctions.map((func: any, idx: number) => ( + // biome-ignore lint/a11y/useButtonType: + + ))} +
+
+ ) + ); + })()} + + {/* Write Functions (payable/nonpayable) */} + {(() => { + const writeFunctions = contractData.abi.filter( + (item: any) => + item.type === "function" && + (item.stateMutability === "payable" || + item.stateMutability === "nonpayable" || + !item.stateMutability), + ); + return ( + writeFunctions.length > 0 && ( +
+
+ Write Functions ({writeFunctions.length}) +
+
+ {writeFunctions.map((func: any, idx: number) => ( + // biome-ignore lint/a11y/useButtonType: + + ))} +
+
+ ) + ); + })()} + + {/* Events */} + {contractData.abi.filter((item: any) => item.type === "event").length > + 0 && ( +
+
+ Events ( + {contractData.abi.filter((item: any) => item.type === "event").length} + ) +
+
+ {contractData.abi + .filter((item: any) => item.type === "event") + .slice(0, 10) + .map((event: any, idx: number) => ( + + key={idx} + style={{ + padding: "4px 10px", + background: "rgba(139, 92, 246, 0.15)", + color: "#8b5cf6", + borderRadius: "6px", + fontSize: "0.8rem", + fontFamily: "monospace", + }} + > + {event.name} + + ))} + {contractData.abi.filter((item: any) => item.type === "event") + .length > 10 && ( + + + + {contractData.abi.filter((item: any) => item.type === "event") + .length - 10}{" "} + more + + )} +
+
+ )} + + {/* Read Function Form */} + {selectedReadFunction && ( +
+
+ {selectedReadFunction.name} +
+ + {selectedReadFunction.inputs && + selectedReadFunction.inputs.length > 0 ? ( +
+ {selectedReadFunction.inputs.map((input: any, idx: number) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+ {/** biome-ignore lint/a11y/noLabelWithoutControl: */} + + + setFunctionInputs({ + ...functionInputs, + [input.name || `param${idx}`]: e.target.value, + }) + } + placeholder={`Enter ${input.type}`} + style={{ + width: "100%", + padding: "8px 12px", + background: "rgba(0, 0, 0, 0.3)", + border: "1px solid rgba(59, 130, 246, 0.3)", + borderRadius: "6px", + color: "#fff", + fontSize: "0.85rem", + fontFamily: "monospace", + }} + /> +
+ ))} +
+ ) : ( +
+ No parameters required +
+ )} + + {/* Read Result */} + {readFunctionResult !== null && ( +
+
+ {readFunctionResult?.startsWith("Error") + ? "❌ Error" + : "βœ… Result"} +
+ {readFunctionResult} +
+ )} + +
+ {/** biome-ignore lint/a11y/useButtonType: */} + + {/** biome-ignore lint/a11y/useButtonType: */} + +
+
+ )} + + {/* Write Function Form */} + {selectedWriteFunction && ( +
+
+ {selectedWriteFunction.name} + {selectedWriteFunction.stateMutability === "payable" && ( + + payable + + )} +
+ + {selectedWriteFunction.inputs && + selectedWriteFunction.inputs.length > 0 ? ( +
+ {selectedWriteFunction.inputs.map((input: any, idx: number) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+ {/** biome-ignore lint/a11y/noLabelWithoutControl: */} + + + setFunctionInputs({ + ...functionInputs, + [input.name || `param${idx}`]: e.target.value, + }) + } + placeholder={`Enter ${input.type}`} + style={{ + width: "100%", + padding: "8px 12px", + background: "rgba(0, 0, 0, 0.3)", + border: "1px solid rgba(245, 158, 11, 0.3)", + borderRadius: "6px", + color: "#fff", + fontSize: "0.85rem", + fontFamily: "monospace", + }} + /> +
+ ))} +
+ ) : ( +
+ No parameters required +
+ )} + + {selectedWriteFunction.stateMutability === "payable" && ( +
+ {/** biome-ignore lint/a11y/noLabelWithoutControl: */} + + + setFunctionInputs({ + ...functionInputs, + _value: e.target.value, + }) + } + placeholder="0.0" + style={{ + width: "100%", + padding: "8px 12px", + background: "rgba(0, 0, 0, 0.3)", + border: "1px solid rgba(16, 185, 129, 0.3)", + borderRadius: "6px", + color: "#fff", + fontSize: "0.85rem", + fontFamily: "monospace", + }} + /> +
+ )} + + {/* Transaction Status */} + {(isPending || isConfirming || isConfirmed || isError) && ( +
+ {isPending && "⏳ Waiting for wallet confirmation..."} + {isConfirming && "⏳ Waiting for transaction confirmation..."} + {isConfirmed && ( +
+ βœ… Transaction confirmed! + {hash && ( +
+ + View transaction + +
+ )} +
+ )} + {isError && ( +
❌ Error: {error?.message || "Transaction failed"}
+ )} +
+ )} + +
+ {/** biome-ignore lint/a11y/useButtonType: */} + + {/** biome-ignore lint/a11y/useButtonType: */} + +
+
+ )} +
+
+ )} + + {sourcifyData && ( + + )} + + )} +
+ )} + + {/* Last Transactions Section */} +
+
+ Last Transactions + {transactionsResult && ( + + {transactionsResult.source === "trace_filter" && ( + <> + ● + Complete history ({transactionDetails.length} transactions) + + )} + {transactionsResult.source === "logs" && ( + <> + ● + Partial (logs only) - {transactionDetails.length} transactions + + )} + {transactionsResult.source === "none" && ( + <> + ● + No data available + + )} + + )} +
+ + {/* Warning message for partial data */} + {transactionsResult?.message && ( +
+ + {transactionsResult.source === "none" ? "⚠️" : "ℹ️"} + + {transactionsResult.message} +
+ )} + + {/* Loading state */} + {loadingTxDetails && ( +
Loading transaction details...
+ )} + + {/* Transaction table */} + {!loadingTxDetails && transactionDetails.length > 0 && ( +
+ + + + + + + + + + + + {transactionDetails.map((tx) => ( + + + + + + + + ))} + +
TX HashFromToValueStatus
+ + {truncate(tx.hash, 8, 6)} + + + + {tx.from?.toLowerCase() === addressHash.toLowerCase() + ? "This Address" + : truncate(tx.from || "", 6, 4)} + + + {tx.to ? ( + + {tx.to?.toLowerCase() === addressHash.toLowerCase() + ? "This Address" + : truncate(tx.to, 6, 4)} + + ) : ( + Contract Creation + )} + + {formatValue(tx.value)} + + {tx.receipt?.status === "0x1" ? ( + + βœ“ Success + + ) : tx.receipt?.status === "0x0" ? ( + βœ— Failed + ) : ( + + ⏳ Pending + + )} +
+
+ )} + + {/* Empty state */} + {!loadingTxDetails && + transactionDetails.length === 0 && + !transactionsResult?.message && ( +
No transactions found for this address
+ )} +
+ + {/* Storage Section (for contracts) */} + {isContract && ( +
+
+ Contract Storage +
+
+
+ Storage Slot: + +
+ setStorageSlot(e.target.value)} + className="storage-input" + /> + {/** biome-ignore lint/a11y/useButtonType: */} + +
+
+
+ {storageValue && ( +
+ Value: + +
{storageValue}
+
+
+ )} +
+
+ )} +
+
+ ); + }, ); AddressDisplay.displayName = "AddressDisplay"; diff --git a/src/components/common/BlockDisplay.tsx b/src/components/common/BlockDisplay.tsx index f7a765a..7d8f09e 100644 --- a/src/components/common/BlockDisplay.tsx +++ b/src/components/common/BlockDisplay.tsx @@ -4,487 +4,444 @@ import type { Block, BlockArbitrum, RPCMetadata } from "../../types"; import { RPCIndicator } from "./RPCIndicator"; interface BlockDisplayProps { - block: Block | BlockArbitrum; - chainId?: string; - metadata?: RPCMetadata; - selectedProvider?: string | null; - onProviderSelect?: (provider: string) => void; + block: Block | BlockArbitrum; + chainId?: string; + metadata?: RPCMetadata; + selectedProvider?: string | null; + onProviderSelect?: (provider: string) => void; } const BlockDisplay: React.FC = React.memo( - ({ block, chainId, metadata, selectedProvider, onProviderSelect }) => { - const [showWithdrawals, setShowWithdrawals] = useState(false); - const [showTransactions, setShowTransactions] = useState(false); - const [showMoreDetails, setShowMoreDetails] = useState(false); - - // Check if this is an Arbitrum block - const isArbitrumBlock = ( - block: Block | BlockArbitrum, - ): block is BlockArbitrum => { - return "l1BlockNumber" in block; - }; - - // Helper to format timestamp - const formatTimestamp = (timestamp: string) => { - try { - const ts = Number(timestamp); - const date = new Date(ts * 1000); - return new Intl.DateTimeFormat(undefined, { - year: "numeric", - month: "short", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - timeZoneName: "short", - }).format(date); - } catch (e) { - return timestamp; - } - }; - - const formatTimeAgo = (timestamp: string) => { - const ts = Number(timestamp) * 1000; - const diffMs = Date.now() - ts; - const diffSeconds = Math.floor(Math.abs(diffMs) / 1000); - - if (diffSeconds < 5) { - return diffMs >= 0 ? "just now" : "in a few seconds"; - } - - const units = [ - { label: "day", seconds: 60 * 60 * 24 }, - { label: "hour", seconds: 60 * 60 }, - { label: "minute", seconds: 60 }, - ]; - - for (const unit of units) { - if (diffSeconds >= unit.seconds) { - const value = Math.floor(diffSeconds / unit.seconds); - const plural = value === 1 ? "" : "s"; - return diffMs >= 0 - ? `${value} ${unit.label}${plural} ago` - : `in ${value} ${unit.label}${plural}`; - } - } - - return diffMs >= 0 - ? `${diffSeconds} second${diffSeconds === 1 ? "" : "s"} ago` - : `in ${diffSeconds} second${diffSeconds === 1 ? "" : "s"}`; - }; - - const formatGwei = (value: string) => { - try { - const gwei = Number(value) / 1e9; - return `${gwei.toFixed(9)} Gwei`; - } catch (e) { - return value; - } - }; - - const formatEth = (value: string) => { - try { - const eth = Number(value) / 1e18; - return `${eth.toFixed(12)} ETH`; - } catch (e) { - return value; - } - }; - - const blockNumber = Number(block.number); - const timestampFormatted = formatTimestamp(block.timestamp); - const timestampAge = formatTimeAgo(block.timestamp); - const gasUsedPct = ( - (Number(block.gasUsed) / Number(block.gasLimit)) * - 100 - ).toFixed(1); - - // Calculate burnt fees if baseFeePerGas exists - const burntFees = block.baseFeePerGas - ? (BigInt(block.gasUsed) * BigInt(block.baseFeePerGas)).toString() - : null; - - return ( -
-
- Block Details - {metadata && selectedProvider !== undefined && onProviderSelect && ( - - )} -
- -
- {/* Block Height */} -
- Block Height: - - - {blockNumber.toLocaleString()} - - {chainId && ( - - {blockNumber > 0 && ( - - ← - - )} - - β†’ - - - )} - -
- - {/* Timestamp */} -
- Timestamp: - - {timestampAge} - ({timestampFormatted}) - -
- - {/* Transactions */} -
- Transactions: - - - {block.transactions ? block.transactions.length : 0}{" "} - transactions - {" "} - in this block - -
- - {/* Withdrawals count */} - {block.withdrawals && block.withdrawals.length > 0 && ( -
- Withdrawals: - - {block.withdrawals.length} withdrawal - {block.withdrawals.length !== 1 ? "s" : ""} in this block - -
- )} - - {/* Fee Recipient (Miner) */} -
- Fee Recipient: - - {chainId ? ( - - {block.miner} - - ) : ( - block.miner - )} - -
- - {/* Gas Used */} -
- Gas Used: - - {Number(block.gasUsed).toLocaleString()} - ({gasUsedPct}%) - -
- - {/* Gas Limit */} -
- Gas Limit: - - {Number(block.gasLimit).toLocaleString()} - -
- - {/* Base Fee Per Gas */} - {block.baseFeePerGas && ( -
- Base Fee Per Gas: - - {formatGwei(block.baseFeePerGas)} - -
- )} - - {/* Burnt Fees */} - {burntFees && ( -
- Burnt Fees: - - πŸ”₯ {formatEth(burntFees)} - -
- )} - - {/* Extra Data */} - {block.extraData && block.extraData !== "0x" && ( -
- Extra Data: - {block.extraData} -
- )} - - {/* Difficulty */} - {Number(block.difficulty) > 0 && ( -
- Difficulty: - - {Number(block.difficulty).toLocaleString()} - -
- )} - - {/* Total Difficulty */} - {Number(block.totalDifficulty) > 0 && ( -
- Total Difficulty: - - {Number(block.totalDifficulty).toLocaleString()} - -
- )} - - {/* Size */} -
- Size: - - {Number(block.size).toLocaleString()} bytes - -
- - {/* Arbitrum-specific fields */} - {isArbitrumBlock(block) && ( - <> -
- L1 Block Number: - - {Number(block.l1BlockNumber).toLocaleString()} - -
-
- Send Count: - {block.sendCount} -
-
- Send Root: - {block.sendRoot} -
- - )} - - {/* More Details (collapsible) */} -
- - - {showMoreDetails && ( -
-
- Hash: - {block.hash} -
-
- Parent Hash: - - {chainId && - block.parentHash !== - "0x0000000000000000000000000000000000000000000000000000000000000000" ? ( - - {block.parentHash} - - ) : ( - block.parentHash - )} - -
-
- State Root: - - {block.stateRoot} - -
-
- Transactions Root: - - {block.transactionsRoot} - -
-
- Receipts Root: - - {block.receiptsRoot} - -
- {block.withdrawalsRoot && ( -
- Withdrawals Root: - - {block.withdrawalsRoot} - -
- )} -
- Logs Bloom: -
- {block.logsBloom} -
-
-
- Nonce: - {block.nonce} -
-
- Mix Hash: - {block.mixHash} -
-
- Sha3 Uncles: - - {block.sha3Uncles} - -
-
- )} -
-
- - {/* Transactions List */} - {block.transactions && block.transactions.length > 0 && ( -
-
- -
- {showTransactions && ( -
- {block.transactions.map((txHash, index) => ( -
- {index} - - {chainId ? ( - - {txHash} - - ) : ( - txHash - )} - -
- ))} -
- )} -
- )} - - {/* Withdrawals List */} - {block.withdrawals && block.withdrawals.length > 0 && ( -
-
- -
- {showWithdrawals && ( -
- {block.withdrawals.map((withdrawal, index) => ( -
-
{index}
-
-
- Index - - {Number(withdrawal.index).toLocaleString()} - -
-
- Validator - - {Number(withdrawal.validatorIndex).toLocaleString()} - -
-
- Address - - {chainId ? ( - - {withdrawal.address} - - ) : ( - withdrawal.address - )} - -
-
- Amount - - {(Number(withdrawal.amount) / 1e9).toFixed(9)} ETH - -
-
-
- ))} -
- )} -
- )} -
- ); - }, + ({ block, chainId, metadata, selectedProvider, onProviderSelect }) => { + const [showWithdrawals, setShowWithdrawals] = useState(false); + const [showTransactions, setShowTransactions] = useState(false); + const [showMoreDetails, setShowMoreDetails] = useState(false); + + // Check if this is an Arbitrum block + const isArbitrumBlock = (block: Block | BlockArbitrum): block is BlockArbitrum => { + return "l1BlockNumber" in block; + }; + + // Helper to format timestamp + const formatTimestamp = (timestamp: string) => { + try { + const ts = Number(timestamp); + const date = new Date(ts * 1000); + return new Intl.DateTimeFormat(undefined, { + year: "numeric", + month: "short", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZoneName: "short", + }).format(date); + } catch (e) { + return timestamp; + } + }; + + const formatTimeAgo = (timestamp: string) => { + const ts = Number(timestamp) * 1000; + const diffMs = Date.now() - ts; + const diffSeconds = Math.floor(Math.abs(diffMs) / 1000); + + if (diffSeconds < 5) { + return diffMs >= 0 ? "just now" : "in a few seconds"; + } + + const units = [ + { label: "day", seconds: 60 * 60 * 24 }, + { label: "hour", seconds: 60 * 60 }, + { label: "minute", seconds: 60 }, + ]; + + for (const unit of units) { + if (diffSeconds >= unit.seconds) { + const value = Math.floor(diffSeconds / unit.seconds); + const plural = value === 1 ? "" : "s"; + return diffMs >= 0 + ? `${value} ${unit.label}${plural} ago` + : `in ${value} ${unit.label}${plural}`; + } + } + + return diffMs >= 0 + ? `${diffSeconds} second${diffSeconds === 1 ? "" : "s"} ago` + : `in ${diffSeconds} second${diffSeconds === 1 ? "" : "s"}`; + }; + + const formatGwei = (value: string) => { + try { + const gwei = Number(value) / 1e9; + return `${gwei.toFixed(9)} Gwei`; + } catch (e) { + return value; + } + }; + + const formatEth = (value: string) => { + try { + const eth = Number(value) / 1e18; + return `${eth.toFixed(12)} ETH`; + } catch (e) { + return value; + } + }; + + const blockNumber = Number(block.number); + const timestampFormatted = formatTimestamp(block.timestamp); + const timestampAge = formatTimeAgo(block.timestamp); + const gasUsedPct = ((Number(block.gasUsed) / Number(block.gasLimit)) * 100).toFixed(1); + + // Calculate burnt fees if baseFeePerGas exists + const burntFees = block.baseFeePerGas + ? (BigInt(block.gasUsed) * BigInt(block.baseFeePerGas)).toString() + : null; + + return ( +
+
+ Block Details + {metadata && selectedProvider !== undefined && onProviderSelect && ( + + )} +
+ +
+ {/* Block Height */} +
+ Block Height: + + {blockNumber.toLocaleString()} + {chainId && ( + + {blockNumber > 0 && ( + + ← + + )} + + β†’ + + + )} + +
+ + {/* Timestamp */} +
+ Timestamp: + + {timestampAge} + ({timestampFormatted}) + +
+ + {/* Transactions */} +
+ Transactions: + + + {block.transactions ? block.transactions.length : 0} transactions + {" "} + in this block + +
+ + {/* Withdrawals count */} + {block.withdrawals && block.withdrawals.length > 0 && ( +
+ Withdrawals: + + {block.withdrawals.length} withdrawal + {block.withdrawals.length !== 1 ? "s" : ""} in this block + +
+ )} + + {/* Fee Recipient (Miner) */} +
+ Fee Recipient: + + {chainId ? ( + + {block.miner} + + ) : ( + block.miner + )} + +
+ + {/* Gas Used */} +
+ Gas Used: + + {Number(block.gasUsed).toLocaleString()} + ({gasUsedPct}%) + +
+ + {/* Gas Limit */} +
+ Gas Limit: + {Number(block.gasLimit).toLocaleString()} +
+ + {/* Base Fee Per Gas */} + {block.baseFeePerGas && ( +
+ Base Fee Per Gas: + {formatGwei(block.baseFeePerGas)} +
+ )} + + {/* Burnt Fees */} + {burntFees && ( +
+ Burnt Fees: + + πŸ”₯ {formatEth(burntFees)} + +
+ )} + + {/* Extra Data */} + {block.extraData && block.extraData !== "0x" && ( +
+ Extra Data: + {block.extraData} +
+ )} + + {/* Difficulty */} + {Number(block.difficulty) > 0 && ( +
+ Difficulty: + {Number(block.difficulty).toLocaleString()} +
+ )} + + {/* Total Difficulty */} + {Number(block.totalDifficulty) > 0 && ( +
+ Total Difficulty: + {Number(block.totalDifficulty).toLocaleString()} +
+ )} + + {/* Size */} +
+ Size: + {Number(block.size).toLocaleString()} bytes +
+ + {/* Arbitrum-specific fields */} + {isArbitrumBlock(block) && ( + <> +
+ L1 Block Number: + {Number(block.l1BlockNumber).toLocaleString()} +
+
+ Send Count: + {block.sendCount} +
+
+ Send Root: + {block.sendRoot} +
+ + )} + + {/* More Details (collapsible) */} +
+ {/** biome-ignore lint/a11y/useButtonType: */} + + + {showMoreDetails && ( +
+
+ Hash: + {block.hash} +
+
+ Parent Hash: + + {chainId && + block.parentHash !== + "0x0000000000000000000000000000000000000000000000000000000000000000" ? ( + + {block.parentHash} + + ) : ( + block.parentHash + )} + +
+
+ State Root: + {block.stateRoot} +
+
+ Transactions Root: + {block.transactionsRoot} +
+
+ Receipts Root: + {block.receiptsRoot} +
+ {block.withdrawalsRoot && ( +
+ Withdrawals Root: + {block.withdrawalsRoot} +
+ )} +
+ Logs Bloom: +
+ {block.logsBloom} +
+
+
+ Nonce: + {block.nonce} +
+
+ Mix Hash: + {block.mixHash} +
+
+ Sha3 Uncles: + {block.sha3Uncles} +
+
+ )} +
+
+ + {/* Transactions List */} + {block.transactions && block.transactions.length > 0 && ( +
+
+ {/** biome-ignore lint/a11y/useButtonType: */} + +
+ {showTransactions && ( +
+ {block.transactions.map((txHash, index) => ( +
+ {index} + + {chainId ? ( + + {txHash} + + ) : ( + txHash + )} + +
+ ))} +
+ )} +
+ )} + + {/* Withdrawals List */} + {block.withdrawals && block.withdrawals.length > 0 && ( +
+
+ {/** biome-ignore lint/a11y/useButtonType: */} + +
+ {showWithdrawals && ( +
+ {block.withdrawals.map((withdrawal, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+
{index}
+
+
+ Index + + {Number(withdrawal.index).toLocaleString()} + +
+
+ Validator + + {Number(withdrawal.validatorIndex).toLocaleString()} + +
+
+ Address + + {chainId ? ( + + {withdrawal.address} + + ) : ( + withdrawal.address + )} + +
+
+ Amount + + {(Number(withdrawal.amount) / 1e9).toFixed(9)} ETH + +
+
+
+ ))} +
+ )} +
+ )} +
+ ); + }, ); BlockDisplay.displayName = "BlockDisplay"; diff --git a/src/components/common/ErrorBoundary.tsx b/src/components/common/ErrorBoundary.tsx index 16b93a8..2e792db 100644 --- a/src/components/common/ErrorBoundary.tsx +++ b/src/components/common/ErrorBoundary.tsx @@ -1,125 +1,127 @@ -import React, { Component, ErrorInfo, ReactNode } from "react"; +import React, { Component, type ErrorInfo, type ReactNode } from "react"; interface Props { - children: ReactNode; - fallback?: ReactNode; + children: ReactNode; + fallback?: ReactNode; } interface State { - hasError: boolean; - error?: Error; - errorInfo?: ErrorInfo; + hasError: boolean; + error?: Error; + errorInfo?: ErrorInfo; } export class ErrorBoundary extends Component { - constructor(props: Props) { - super(props); - this.state = { hasError: false }; - } - - static getDerivedStateFromError(error: Error): State { - // Update state so the next render will show the fallback UI - return { hasError: true, error }; - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo) { - // Log error details - console.error("ErrorBoundary caught an error:", error, errorInfo); - - this.setState({ - error, - errorInfo, - }); - - // You can also log the error to an error reporting service here - // Example: errorReportingService.captureException(error, { extra: errorInfo }); - } - - private handleReload = () => { - window.location.reload(); - }; - - private handleGoHome = () => { - window.location.href = "/"; - }; - - render() { - if (this.state.hasError) { - // Custom fallback UI - if (this.props.fallback) { - return this.props.fallback; - } - - // Default error UI - return ( -
-
-
-

⚠️ Something went wrong

-

- We're sorry, but something unexpected happened. The application - encountered an error. -

- -
- - -
- - {process.env.NODE_ENV === "development" && this.state.error && ( -
- Error Details (Development Mode) -
-

Error:

-
{this.state.error.toString()}
- - {this.state.errorInfo && ( - <> -

Component Stack:

-
{this.state.errorInfo.componentStack}
- - )} -
-
- )} -
-
-
- ); - } - - return this.props.children; - } + constructor(props: Props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error: Error): State { + // Update state so the next render will show the fallback UI + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + // Log error details + console.error("ErrorBoundary caught an error:", error, errorInfo); + + this.setState({ + error, + errorInfo, + }); + + // You can also log the error to an error reporting service here + // Example: errorReportingService.captureException(error, { extra: errorInfo }); + } + + private handleReload = () => { + window.location.reload(); + }; + + private handleGoHome = () => { + window.location.href = "/"; + }; + + render() { + if (this.state.hasError) { + // Custom fallback UI + if (this.props.fallback) { + return this.props.fallback; + } + + // Default error UI + return ( +
+
+
+

⚠️ Something went wrong

+

+ We're sorry, but something unexpected happened. The application encountered an + error. +

+ +
+ {/** biome-ignore lint/a11y/useButtonType: */} + + {/** biome-ignore lint/a11y/useButtonType: */} + +
+ + {process.env.NODE_ENV === "development" && this.state.error && ( +
+ Error Details (Development Mode) +
+

Error:

+
{this.state.error.toString()}
+ + {this.state.errorInfo && ( + <> +

Component Stack:

+
{this.state.errorInfo.componentStack}
+ + )} +
+
+ )} +
+
+
+ ); + } + + return this.props.children; + } } // Hook version for functional components that need error boundary functionality export const useErrorHandler = () => { - const [error, setError] = React.useState(null); - - const resetError = React.useCallback(() => { - setError(null); - }, []); - - const captureError = React.useCallback((error: Error) => { - console.error("Error captured:", error); - setError(error); - }, []); - - React.useEffect(() => { - if (error) { - throw error; - } - }, [error]); - - return { - captureError, - resetError, - hasError: !!error, - }; + const [error, setError] = React.useState(null); + + const resetError = React.useCallback(() => { + setError(null); + }, []); + + const captureError = React.useCallback((error: Error) => { + console.error("Error captured:", error); + setError(error); + }, []); + + React.useEffect(() => { + if (error) { + throw error; + } + }, [error]); + + return { + captureError, + resetError, + hasError: !!error, + }; }; export default ErrorBoundary; diff --git a/src/components/common/Footer.tsx b/src/components/common/Footer.tsx index 128bc32..0836806 100644 --- a/src/components/common/Footer.tsx +++ b/src/components/common/Footer.tsx @@ -1,73 +1,73 @@ -import React from "react"; +import type React from "react"; import { Link } from "react-router-dom"; import { ENVIRONMENT } from "../../utils/constants"; interface FooterProps { - className?: string; + className?: string; } const Footer: React.FC = ({ className = "" }) => { - // Get commit hash from environment variable, fallback to 'development' - const commitHash = process.env.REACT_APP_COMMIT_HASH || "development"; + // Get commit hash from environment variable, fallback to 'development' + const commitHash = process.env.REACT_APP_COMMIT_HASH || "development"; - // Format commit hash - show first 7 characters if it's a full hash - const formattedCommitHash = - commitHash.length > 7 ? commitHash.substring(0, 7) : commitHash; + // Format commit hash - show first 7 characters if it's a full hash + const formattedCommitHash = commitHash.length > 7 ? commitHash.substring(0, 7) : commitHash; - // Get version from environment variable or fallback - const appVersion = process.env.REACT_APP_VERSION || "0.1.0"; + // Get version from environment variable or fallback + const appVersion = process.env.REACT_APP_VERSION || "0.1.0"; - // Get the GitHub repository URL from package.json or environment - const repoUrl = - process.env.REACT_APP_GITHUB_REPO || "https://github.com/openscan-explorer/explorer"; + // Get the GitHub repository URL from package.json or environment + const repoUrl = + process.env.REACT_APP_GITHUB_REPO || "https://github.com/openscan-explorer/explorer"; - // Determine footer version class based on environment - const getVersionClass = () => { - if (ENVIRONMENT === "staging") return "footer-version-staging"; - if (ENVIRONMENT === "development") return "footer-version-development"; - return ""; - }; - return ( - - ); + // Determine footer version class based on environment + const getVersionClass = () => { + if (ENVIRONMENT === "staging") return "footer-version-staging"; + if (ENVIRONMENT === "development") return "footer-version-development"; + return ""; + }; + return ( + + ); }; export default Footer; diff --git a/src/components/common/IsometricBlocks.tsx b/src/components/common/IsometricBlocks.tsx index fe97bcb..f42a16a 100644 --- a/src/components/common/IsometricBlocks.tsx +++ b/src/components/common/IsometricBlocks.tsx @@ -1,162 +1,139 @@ -import React, { - useState, - useEffect, - useCallback, - useMemo, - useRef, -} from "react"; +import type React from "react"; +import { useState, useEffect, useCallback, useMemo, useRef } from "react"; // Network colors matching the logo - Ethereum weighted more heavily const NETWORKS = [ - { color: "#627EEA", weight: 70 }, // Ethereum - most common - { color: "#FFF100", weight: 6 }, // Hardhat/Local - { color: "#28A0F0", weight: 6 }, // Arbitrum - { color: "#FF0420", weight: 6 }, // Optimism - { color: "#0052FF", weight: 6 }, // Base - { color: "#CFB4FF", weight: 6 }, // Sepolia + { color: "#627EEA", weight: 70 }, // Ethereum - most common + { color: "#FFF100", weight: 6 }, // Hardhat/Local + { color: "#28A0F0", weight: 6 }, // Arbitrum + { color: "#FF0420", weight: 6 }, // Optimism + { color: "#0052FF", weight: 6 }, // Base + { color: "#CFB4FF", weight: 6 }, // Sepolia ]; // Create weighted array for random selection const WEIGHTED_COLORS = NETWORKS.flatMap((n) => Array(n.weight).fill(n.color)); interface CubeData { - id: number; - x: number; - y: number; - color: string; + id: number; + x: number; + y: number; + color: string; } interface IsometricCubeProps { - x: number; - y: number; - size: number; - color: string; + x: number; + y: number; + size: number; + color: string; } const IsometricCube: React.FC = ({ x, y, size, color }) => { - // Isometric cube dimensions - const h = size * 0.5; // height offset for 3D effect - - // Top face (brightest) - const topPoints = `${x},${y - h} ${x + size},${y} ${x},${y + h} ${x - size},${y}`; - - // Left face (medium) - const leftPoints = `${x - size},${y} ${x},${y + h} ${x},${y + h + size} ${x - size},${y + size}`; - - // Right face (darkest) - const rightPoints = `${x},${y + h} ${x + size},${y} ${x + size},${y + size} ${x},${y + h + size}`; - - return ( - - {/* Right face - darkest */} - - {/* Left face - medium */} - - {/* Top face - brightest */} - - - ); + // Isometric cube dimensions + const h = size * 0.5; // height offset for 3D effect + + // Top face (brightest) + const topPoints = `${x},${y - h} ${x + size},${y} ${x},${y + h} ${x - size},${y}`; + + // Left face (medium) + const leftPoints = `${x - size},${y} ${x},${y + h} ${x},${y + h + size} ${x - size},${y + size}`; + + // Right face (darkest) + const rightPoints = `${x},${y + h} ${x + size},${y} ${x + size},${y + size} ${x},${y + h + size}`; + + return ( + + {/* Right face - darkest */} + + {/* Left face - medium */} + + {/* Top face - brightest */} + + + ); }; interface IsometricBlocksProps { - width: number; - height: number; - cubeSize?: number; - maxCubes?: number; - spawnInterval?: number; + width: number; + height: number; + cubeSize?: number; + maxCubes?: number; + spawnInterval?: number; } export const IsometricBlocks: React.FC = ({ - width, - height, - cubeSize = 24, - maxCubes = 50, - spawnInterval = 400, + width, + height, + cubeSize = 24, + maxCubes = 50, + spawnInterval = 400, }) => { - const [cubes, setCubes] = useState([]); - const nextIdRef = useRef(0); - - // Calculate grid positions for isometric layout - const gridPositions = useMemo(() => { - const positions: { x: number; y: number }[] = []; - const stepX = cubeSize * 2; - const stepY = cubeSize * 1.5; - - for (let row = -2; row < height / stepY + 2; row++) { - const offsetX = (row % 2) * cubeSize; - for (let col = -2; col < width / stepX + 2; col++) { - positions.push({ - x: col * stepX + offsetX + cubeSize, - y: row * stepY + cubeSize, - }); - } - } - return positions; - }, [width, height, cubeSize]); - - // Spawn new cubes periodically - const spawnCube = useCallback(() => { - const pos = gridPositions[Math.floor(Math.random() * gridPositions.length)]; - if (!pos) return; - const network = - WEIGHTED_COLORS[Math.floor(Math.random() * WEIGHTED_COLORS.length)]; - if (!network) return; - - const cubeId = nextIdRef.current++; - const newCube: CubeData = { - id: cubeId, - x: pos.x, - y: pos.y, - color: network, - }; - - setCubes((prev) => { - const updated = [...prev, newCube]; - // Remove oldest cubes if we exceed max - if (updated.length > maxCubes) { - return updated.slice(-maxCubes); - } - return updated; - }); - }, [gridPositions, maxCubes]); - - // Spawn cubes periodically - useEffect(() => { - const spawn = setInterval(spawnCube, spawnInterval); - return () => clearInterval(spawn); - }, [spawnCube, spawnInterval]); - - return ( - - + {cubes.map((cube) => ( + + ))} + + ); }; export default IsometricBlocks; diff --git a/src/components/common/Loader.tsx b/src/components/common/Loader.tsx index a2022ad..f7a315f 100644 --- a/src/components/common/Loader.tsx +++ b/src/components/common/Loader.tsx @@ -1,29 +1,27 @@ import React from "react"; interface LoaderProps { - size?: number; - color?: string; - text?: string; + size?: number; + color?: string; + text?: string; } -const Loader: React.FC = React.memo( - ({ size = 40, color = "#10b981", text }) => { - return ( -
-
- {text &&

{text}

} -
- ); - }, -); +const Loader: React.FC = React.memo(({ size = 40, color = "#10b981", text }) => { + return ( +
+
+ {text &&

{text}

} +
+ ); +}); Loader.displayName = "Loader"; diff --git a/src/components/common/Loading.tsx b/src/components/common/Loading.tsx index ddee629..703a51a 100644 --- a/src/components/common/Loading.tsx +++ b/src/components/common/Loading.tsx @@ -2,13 +2,13 @@ import React from "react"; import "../../styles/styles.css"; const Loading = React.memo(() => ( -
-
-
-
-
-
-
+
+
+
+
+
+
+
)); Loading.displayName = "Loading"; diff --git a/src/components/common/LongString.tsx b/src/components/common/LongString.tsx index 4b6eafc..c59939a 100644 --- a/src/components/common/LongString.tsx +++ b/src/components/common/LongString.tsx @@ -1,43 +1,40 @@ -import React, { useState } from "react"; +import type React from "react"; +import { useState } from "react"; interface LongStringProps { - value: string; - start?: number; - end?: number; - style?: React.CSSProperties; + value: string; + start?: number; + end?: number; + style?: React.CSSProperties; } -const LongString: React.FC = ({ - value, - start = 10, - end = 8, - style = {}, -}) => { - const [isHovered, setIsHovered] = useState(false); +const LongString: React.FC = ({ value, start = 10, end = 8, style = {} }) => { + const [isHovered, setIsHovered] = useState(false); - const truncate = (str: string) => { - if (!str) return ""; - if (str.length <= start + end) return str; - return `${str.slice(0, start)}...${str.slice(-end)}`; - }; + const truncate = (str: string) => { + if (!str) return ""; + if (str.length <= start + end) return str; + return `${str.slice(0, start)}...${str.slice(-end)}`; + }; - const shouldTruncate = value && value.length > start + end; + const shouldTruncate = value && value.length > start + end; - return ( - setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - style={{ - wordBreak: isHovered && shouldTruncate ? "break-all" : "normal", - transition: "all 0.2s ease", - cursor: shouldTruncate ? "pointer" : "default", - ...style, - }} - title={shouldTruncate ? value : undefined} - > - {isHovered && shouldTruncate ? value : truncate(value)} - - ); + return ( + // biome-ignore lint/a11y/noStaticElementInteractions: + setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + style={{ + wordBreak: isHovered && shouldTruncate ? "break-all" : "normal", + transition: "all 0.2s ease", + cursor: shouldTruncate ? "pointer" : "default", + ...style, + }} + title={shouldTruncate ? value : undefined} + > + {isHovered && shouldTruncate ? value : truncate(value)} + + ); }; export default LongString; diff --git a/src/components/common/Navbar.tsx b/src/components/common/Navbar.tsx index 80ad316..21e8897 100644 --- a/src/components/common/Navbar.tsx +++ b/src/components/common/Navbar.tsx @@ -6,239 +6,217 @@ import { NetworkBlockIndicator } from "./NetworkBlockIndicator"; import VersionWarningIcon from "./VersionWarningIcon"; const Navbar = () => { - const { address } = useAccount(); - const navigate = useNavigate(); - const location = useLocation(); - const [searchInput, setSearchInput] = useState(""); + const { address } = useAccount(); + const navigate = useNavigate(); + const location = useLocation(); + const [searchInput, setSearchInput] = useState(""); - // Extract chainId from the pathname (e.g., /1/blocks -> 1) - const pathSegments = location.pathname.split("/").filter(Boolean); - const chainId = - pathSegments[0] && !isNaN(Number(pathSegments[0])) - ? pathSegments[0] - : undefined; + // Extract chainId from the pathname (e.g., /1/blocks -> 1) + const pathSegments = location.pathname.split("/").filter(Boolean); + const chainId = pathSegments[0] && !isNaN(Number(pathSegments[0])) ? pathSegments[0] : undefined; - // Check if we should show the search box (on blocks, block, txs, tx pages) - const shouldShowSearch = - chainId && - pathSegments.length >= 2 && - pathSegments[1] && - ["blocks", "block", "txs", "tx", "address"].includes(pathSegments[1]); + // Check if we should show the search box (on blocks, block, txs, tx pages) + const shouldShowSearch = + chainId && + pathSegments.length >= 2 && + pathSegments[1] && + ["blocks", "block", "txs", "tx", "address"].includes(pathSegments[1]); - console.log( - "Navbar chainId from URL:", - chainId, - "pathname:", - location.pathname, - ); + console.log("Navbar chainId from URL:", chainId, "pathname:", location.pathname); - const handleSearch = (e: React.FormEvent) => { - e.preventDefault(); - if (!searchInput.trim() || !chainId) return; + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + if (!searchInput.trim() || !chainId) return; - const input = searchInput.trim(); + const input = searchInput.trim(); - // Check if it's a transaction hash (0x followed by 64 hex chars) - if (/^0x[a-fA-F0-9]{64}$/.test(input)) { - navigate(`/${chainId}/tx/${input}`); - } - // Check if it's an address (0x followed by 40 hex chars) - else if (/^0x[a-fA-F0-9]{40}$/.test(input)) { - navigate(`/${chainId}/address/${input}`); - } - // Check if it's a block number - else if (/^\d+$/.test(input)) { - navigate(`/${chainId}/block/${input}`); - } - // Check if it's a block hash (0x followed by 64 hex chars - same as tx) - else if (/^0x[a-fA-F0-9]{64}$/.test(input)) { - navigate(`/${chainId}/block/${input}`); - } + // Check if it's a transaction hash (0x followed by 64 hex chars) + if (/^0x[a-fA-F0-9]{64}$/.test(input)) { + navigate(`/${chainId}/tx/${input}`); + } + // Check if it's an address (0x followed by 40 hex chars) + else if (/^0x[a-fA-F0-9]{40}$/.test(input)) { + navigate(`/${chainId}/address/${input}`); + } + // Check if it's a block number + else if (/^\d+$/.test(input)) { + navigate(`/${chainId}/block/${input}`); + } + // Check if it's a block hash (0x followed by 64 hex chars - same as tx) + // biome-ignore lint/suspicious/noDuplicateElseIf: + else if (/^0x[a-fA-F0-9]{64}$/.test(input)) { + navigate(`/${chainId}/block/${input}`); + } - setSearchInput(""); - }; + setSearchInput(""); + }; - const goToSettings = () => { - navigate("/settings"); - }; + const goToSettings = () => { + navigate("/settings"); + }; - return ( - + ); }; export default Navbar; diff --git a/src/components/common/NetworkBlockIndicator.tsx b/src/components/common/NetworkBlockIndicator.tsx index f8e1713..8f1e4a3 100644 --- a/src/components/common/NetworkBlockIndicator.tsx +++ b/src/components/common/NetworkBlockIndicator.tsx @@ -11,180 +11,145 @@ import baseLogo from "../../assets/base-logo.svg"; import hardhatLogo from "../../assets/hardhat-logo.svg"; interface NetworkInfo { - name: string; - logo: string | null; - color: string; + name: string; + logo: string | null; + color: string; } const NETWORK_INFO: Record = { - 1: { name: "Ethereum", logo: null, color: "#627EEA" }, - 11155111: { name: "Sepolia", logo: null, color: "#F0CDC2" }, - 42161: { name: "Arbitrum", logo: arbitrumLogo, color: "#28A0F0" }, - 10: { name: "Optimism", logo: optimismLogo, color: "#FF0420" }, - 8453: { name: "Base", logo: baseLogo, color: "#0052FF" }, - 56: { name: "BSC", logo: "bsc", color: "#F0B90B" }, - 97: { name: "BSC Testnet", logo: "bsc", color: "#F0B90B" }, - 137: { name: "Polygon", logo: "polygon", color: "#8247E5" }, - 31337: { name: "Localhost", logo: hardhatLogo, color: "#FFF100" }, + 1: { name: "Ethereum", logo: null, color: "#627EEA" }, + 11155111: { name: "Sepolia", logo: null, color: "#F0CDC2" }, + 42161: { name: "Arbitrum", logo: arbitrumLogo, color: "#28A0F0" }, + 10: { name: "Optimism", logo: optimismLogo, color: "#FF0420" }, + 8453: { name: "Base", logo: baseLogo, color: "#0052FF" }, + 56: { name: "BSC", logo: "bsc", color: "#F0B90B" }, + 97: { name: "BSC Testnet", logo: "bsc", color: "#F0B90B" }, + 137: { name: "Polygon", logo: "polygon", color: "#8247E5" }, + 31337: { name: "Localhost", logo: hardhatLogo, color: "#FFF100" }, }; // Ethereum SVG for networks without a logo const EthereumIcon = ({ color }: { color: string }) => ( - - - - - - + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + + + + ); // BSC/BNB SVG icon -const BscIcon = ({ - color, - opacity = 1, -}: { - color: string; - opacity?: number; -}) => ( - - - - +const BscIcon = ({ color, opacity = 1 }: { color: string; opacity?: number }) => ( + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + + ); // Polygon SVG icon const PolygonIcon = ({ color }: { color: string }) => ( - - - + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + ); interface NetworkBlockIndicatorProps { - className?: string; + className?: string; } -export function NetworkBlockIndicator({ - className, -}: NetworkBlockIndicatorProps) { - const location = useLocation(); - const { rpcUrls } = useContext(AppContext); - const [blockNumber, setBlockNumber] = useState(null); - const [isLoading, setIsLoading] = useState(false); - - // Extract chainId from the pathname (e.g., /1/blocks -> 1) - const chainId = useMemo(() => { - const pathSegments = location.pathname.split("/").filter(Boolean); - return pathSegments[0] && !isNaN(Number(pathSegments[0])) - ? Number(pathSegments[0]) - : null; - }, [location.pathname]); - - const networkInfo = chainId ? NETWORK_INFO[chainId] : null; - - useEffect(() => { - if (!chainId) { - setBlockNumber(null); - return; - } - - let isMounted = true; - let intervalId: NodeJS.Timeout | null = null; - - const fetchBlockNumber = async () => { - try { - const urls = getRPCUrls(chainId, rpcUrls); - const client = new RPCClient(urls); - const result = await client.call("eth_blockNumber", []); - if (isMounted) { - setBlockNumber(parseInt(result, 16)); - setIsLoading(false); - } - } catch (error) { - console.error("Failed to fetch block number:", error); - if (isMounted) { - setIsLoading(false); - } - } - }; - - setIsLoading(true); - fetchBlockNumber(); - - // Poll for new blocks every 12 seconds (Ethereum average block time) - intervalId = setInterval(fetchBlockNumber, 12000); - - return () => { - isMounted = false; - if (intervalId) { - clearInterval(intervalId); - } - }; - }, [chainId, rpcUrls]); - - if (!chainId || !networkInfo) return null; - - return ( -
-
-
- {networkInfo.logo === "bsc" ? ( - - ) : networkInfo.logo === "polygon" ? ( - - ) : networkInfo.logo ? ( - {networkInfo.name} - ) : ( - - )} -
- - {isLoading - ? "..." - : blockNumber !== null - ? `#${blockNumber.toLocaleString()}` - : "---"} - -
- ); +export function NetworkBlockIndicator({ className }: NetworkBlockIndicatorProps) { + const location = useLocation(); + const { rpcUrls } = useContext(AppContext); + const [blockNumber, setBlockNumber] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + // Extract chainId from the pathname (e.g., /1/blocks -> 1) + const chainId = useMemo(() => { + const pathSegments = location.pathname.split("/").filter(Boolean); + return pathSegments[0] && !isNaN(Number(pathSegments[0])) ? Number(pathSegments[0]) : null; + }, [location.pathname]); + + const networkInfo = chainId ? NETWORK_INFO[chainId] : null; + + useEffect(() => { + if (!chainId) { + setBlockNumber(null); + return; + } + + let isMounted = true; + let intervalId: NodeJS.Timeout | null = null; + + const fetchBlockNumber = async () => { + try { + const urls = getRPCUrls(chainId, rpcUrls); + const client = new RPCClient(urls); + const result = await client.call("eth_blockNumber", []); + if (isMounted) { + setBlockNumber(parseInt(result, 16)); + setIsLoading(false); + } + } catch (error) { + console.error("Failed to fetch block number:", error); + if (isMounted) { + setIsLoading(false); + } + } + }; + + setIsLoading(true); + fetchBlockNumber(); + + // Poll for new blocks every 12 seconds (Ethereum average block time) + intervalId = setInterval(fetchBlockNumber, 12000); + + return () => { + isMounted = false; + if (intervalId) { + clearInterval(intervalId); + } + }; + }, [chainId, rpcUrls]); + + if (!chainId || !networkInfo) return null; + + return ( +
+
+
+ {networkInfo.logo === "bsc" ? ( + + ) : networkInfo.logo === "polygon" ? ( + + ) : networkInfo.logo ? ( + {networkInfo.name} + ) : ( + + )} +
+ + {isLoading ? "..." : blockNumber !== null ? `#${blockNumber.toLocaleString()}` : "---"} + +
+ ); } export default NetworkBlockIndicator; diff --git a/src/components/common/NetworkIcon.tsx b/src/components/common/NetworkIcon.tsx index d4b8ed8..b62b13a 100644 --- a/src/components/common/NetworkIcon.tsx +++ b/src/components/common/NetworkIcon.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import type React from "react"; import arbitrumLogo from "../../assets/arbitrum-logo.svg"; import optimismLogo from "../../assets/optimism-logo.svg"; import baseLogo from "../../assets/base-logo.svg"; @@ -6,111 +6,72 @@ import hardhatLogo from "../../assets/hardhat-logo.svg"; import type { NetworkConfig } from "../../config/networks"; interface NetworkIconProps { - network: NetworkConfig; - size?: number; + network: NetworkConfig; + size?: number; } // Ethereum SVG icon -const EthereumIcon: React.FC<{ color: string; size: number }> = ({ - color, - size, -}) => ( - - - - - - +const EthereumIcon: React.FC<{ color: string; size: number }> = ({ color, size }) => ( + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + + + + ); // BSC/BNB SVG icon const BscIcon: React.FC<{ color: string; size: number; opacity?: number }> = ({ - color, - size, - opacity = 1, + color, + size, + opacity = 1, }) => ( - - - - + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + + ); // Polygon SVG icon -const PolygonIcon: React.FC<{ color: string; size: number }> = ({ - color, - size, -}) => ( - - - +const PolygonIcon: React.FC<{ color: string; size: number }> = ({ color, size }) => ( + // biome-ignore lint/a11y/noSvgWithoutTitle: + + + ); -export const NetworkIcon: React.FC = ({ - network, - size = 32, -}) => { - switch (network.logoType) { - case "ethereum": - return ; - case "bsc": - return ( - - ); - case "polygon": - return ; - case "arbitrum": - return ( - Arbitrum - ); - case "optimism": - return ( - Optimism - ); - case "base": - return Base; - case "hardhat": - return ( - Localhost - ); - default: - return ; - } +export const NetworkIcon: React.FC = ({ network, size = 32 }) => { + switch (network.logoType) { + case "ethereum": + return ; + case "bsc": + return ; + case "polygon": + return ; + case "arbitrum": + return Arbitrum; + case "optimism": + return Optimism; + case "base": + return Base; + case "hardhat": + return Localhost; + default: + return ; + } }; export default NetworkIcon; diff --git a/src/components/common/NetworkStatsDisplay.tsx b/src/components/common/NetworkStatsDisplay.tsx index 4912fde..044fce3 100644 --- a/src/components/common/NetworkStatsDisplay.tsx +++ b/src/components/common/NetworkStatsDisplay.tsx @@ -3,211 +3,199 @@ import type { NetworkStats, RPCMetadata } from "../../types"; import { RPCIndicator } from "./RPCIndicator"; interface NetworkStatsDisplayProps { - networkStats: NetworkStats | null; - loading?: boolean; - error?: string | null; - chainId?: number; - metadata?: RPCMetadata; - selectedProvider?: string | null; - onProviderSelect?: (provider: string) => void; + networkStats: NetworkStats | null; + loading?: boolean; + error?: string | null; + chainId?: number; + metadata?: RPCMetadata; + selectedProvider?: string | null; + onProviderSelect?: (provider: string) => void; } const NetworkStatsDisplay: React.FC = React.memo( - ({ - networkStats, - loading = false, - error = null, - chainId, - metadata, - selectedProvider, - onProviderSelect, - }) => { - if (loading) { - return ( -
-
-
- Loading network statistics... -
-
-
- ); - } - - if (error) { - return ( -
-
-
- Error loading network stats: {error} -
-
-
- ); - } - - if (!networkStats) { - return null; - } - - // Format gas price from Wei to Gwei - const formatGasPrice = (weiPrice: string): string => { - try { - const gwei = Number(weiPrice) / 1e9; - return `${gwei.toFixed(2)} Gwei`; - } catch { - return weiPrice; - } - }; - - // Format block number with commas - const formatBlockNumber = (blockNumber: string): string => { - try { - return Number(blockNumber).toLocaleString(); - } catch { - return blockNumber; - } - }; - - // Parse protocol version from metadata (localhost/Hardhat only) - const getProtocolVersion = (): string | null => { - if (chainId !== 31337 || !networkStats.metadata) { - return null; - } - - try { - return networkStats.metadata.clientVersion || null; - } catch (err) { - console.error("Failed to parse metadata:", err); - return null; - } - }; - - // Get forked network info (localhost/Hardhat only) - const getForkedNetworkInfo = (): { - chainId: number; - blockNumber: number; - blockHash: string; - } | null => { - if ( - chainId !== 31337 || - !networkStats.metadata || - !networkStats.metadata.forkedNetwork - ) { - return null; - } - - try { - const forked = networkStats.metadata.forkedNetwork; - return { - chainId: forked.chainId, - blockNumber: forked.forkBlockNumber, - blockHash: forked.forkBlockHash, - }; - } catch (err) { - console.error("Failed to parse forked network info:", err); - return null; - } - }; - - const protocolVersion = getProtocolVersion(); - const forkedNetwork = getForkedNetworkInfo(); - - return ( -
-
-
-

- Network Statistics -

- {metadata && selectedProvider !== undefined && onProviderSelect && ( - - )} -
- -
-
- Current Gas Price - - {formatGasPrice(networkStats.currentGasPrice)} - -
- -
- Current Block Number - - {formatBlockNumber(networkStats.currentBlockNumber)} - -
- -
- Sync Status - - - - {networkStats.isSyncing ? "Syncing" : "Synced"} - - -
- - {networkStats.clientVersion && ( -
- Client Version - - {networkStats.clientVersion} - -
- )} - - {protocolVersion && ( -
- Protocol Version - {protocolVersion} -
- )} - - {forkedNetwork && ( - <> -
- Forked Network - - Chain ID: {forkedNetwork.chainId} - -
- -
- Fork Block Number - - {formatBlockNumber(forkedNetwork.blockNumber.toString())} - -
- -
- Fork Block Hash - - {forkedNetwork.blockHash} - -
- - )} -
-
-
- ); - }, + ({ + networkStats, + loading = false, + error = null, + chainId, + metadata, + selectedProvider, + onProviderSelect, + }) => { + if (loading) { + return ( +
+
+
Loading network statistics...
+
+
+ ); + } + + if (error) { + return ( +
+
+
+ Error loading network stats: {error} +
+
+
+ ); + } + + if (!networkStats) { + return null; + } + + // Format gas price from Wei to Gwei + const formatGasPrice = (weiPrice: string): string => { + try { + const gwei = Number(weiPrice) / 1e9; + return `${gwei.toFixed(2)} Gwei`; + } catch { + return weiPrice; + } + }; + + // Format block number with commas + const formatBlockNumber = (blockNumber: string): string => { + try { + return Number(blockNumber).toLocaleString(); + } catch { + return blockNumber; + } + }; + + // Parse protocol version from metadata (localhost/Hardhat only) + const getProtocolVersion = (): string | null => { + if (chainId !== 31337 || !networkStats.metadata) { + return null; + } + + try { + return networkStats.metadata.clientVersion || null; + } catch (err) { + console.error("Failed to parse metadata:", err); + return null; + } + }; + + // Get forked network info (localhost/Hardhat only) + const getForkedNetworkInfo = (): { + chainId: number; + blockNumber: number; + blockHash: string; + } | null => { + if (chainId !== 31337 || !networkStats.metadata || !networkStats.metadata.forkedNetwork) { + return null; + } + + try { + const forked = networkStats.metadata.forkedNetwork; + return { + chainId: forked.chainId, + blockNumber: forked.forkBlockNumber, + blockHash: forked.forkBlockHash, + }; + } catch (err) { + console.error("Failed to parse forked network info:", err); + return null; + } + }; + + const protocolVersion = getProtocolVersion(); + const forkedNetwork = getForkedNetworkInfo(); + + return ( +
+
+
+

+ Network Statistics +

+ {metadata && selectedProvider !== undefined && onProviderSelect && ( + + )} +
+ +
+
+ Current Gas Price + {formatGasPrice(networkStats.currentGasPrice)} +
+ +
+ Current Block Number + + {formatBlockNumber(networkStats.currentBlockNumber)} + +
+ +
+ Sync Status + + + + {networkStats.isSyncing ? "Syncing" : "Synced"} + + +
+ + {networkStats.clientVersion && ( +
+ Client Version + {networkStats.clientVersion} +
+ )} + + {protocolVersion && ( +
+ Protocol Version + {protocolVersion} +
+ )} + + {forkedNetwork && ( + <> +
+ Forked Network + Chain ID: {forkedNetwork.chainId} +
+ +
+ Fork Block Number + + {formatBlockNumber(forkedNetwork.blockNumber.toString())} + +
+ +
+ Fork Block Hash + + {forkedNetwork.blockHash} + +
+ + )} +
+
+
+ ); + }, ); NetworkStatsDisplay.displayName = "NetworkStatsDisplay"; diff --git a/src/components/common/NotificationDisplay.tsx b/src/components/common/NotificationDisplay.tsx index 0980fc8..4eab1a8 100644 --- a/src/components/common/NotificationDisplay.tsx +++ b/src/components/common/NotificationDisplay.tsx @@ -2,35 +2,31 @@ import React from "react"; import { useNotifications } from "../../context/NotificationContext"; const NotificationDisplay: React.FC = React.memo(() => { - const { notifications, removeNotification } = useNotifications(); + const { notifications, removeNotification } = useNotifications(); - if (notifications.length === 0) { - return null; - } + if (notifications.length === 0) { + return null; + } - return ( -
- {notifications.map((notification) => ( -
-
- - {notification.message} - - -
-
- ))} -
- ); + return ( +
+ {notifications.map((notification) => ( +
+
+ {notification.message} + {/** biome-ignore lint/a11y/useButtonType: */} + +
+
+ ))} +
+ ); }); NotificationDisplay.displayName = "NotificationDisplay"; diff --git a/src/components/common/RPCIndicator.tsx b/src/components/common/RPCIndicator.tsx index 9475f1a..bdbab64 100644 --- a/src/components/common/RPCIndicator.tsx +++ b/src/components/common/RPCIndicator.tsx @@ -2,10 +2,10 @@ import { useState, useRef, useEffect } from "react"; import type { RPCMetadata } from "../../types"; interface RPCIndicatorProps { - metadata: RPCMetadata; - selectedProvider: string | null; - onProviderSelect: (url: string) => void; - className?: string; + metadata: RPCMetadata; + selectedProvider: string | null; + onProviderSelect: (url: string) => void; + className?: string; } /** @@ -13,131 +13,117 @@ interface RPCIndicatorProps { * Expands on click to show detailed provider information */ export function RPCIndicator({ - metadata, - selectedProvider, - onProviderSelect, - className, + metadata, + selectedProvider, + onProviderSelect, + className, }: RPCIndicatorProps) { - const [isExpanded, setIsExpanded] = useState(false); - const dropdownRef = useRef(null); + const [isExpanded, setIsExpanded] = useState(false); + const dropdownRef = useRef(null); - const successCount = metadata.responses.filter( - (r) => r.status === "success", - ).length; - const totalCount = metadata.responses.length; + const successCount = metadata.responses.filter((r) => r.status === "success").length; + const totalCount = metadata.responses.length; - // Close dropdown when clicking outside - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) - ) { - setIsExpanded(false); - } - }; - document.addEventListener("mousedown", handleClickOutside); - return () => document.removeEventListener("mousedown", handleClickOutside); - }, []); + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsExpanded(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); - return ( -
- {/* Compact Badge */} -
setIsExpanded(!isExpanded)} - title="Click to see RPC provider details" - > - {metadata.hasInconsistencies && ( - - ⚠️ - - )} - - βœ“ {successCount}/{totalCount} - -
+ return ( +
+ {/* Compact Badge */} + {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
setIsExpanded(!isExpanded)} + title="Click to see RPC provider details" + > + {metadata.hasInconsistencies && ( + + ⚠️ + + )} + + βœ“ {successCount}/{totalCount} + +
- {/* Expanded Dropdown */} - {isExpanded && ( -
-
- RPC Providers - - Strategy: {metadata.strategy} - -
+ {/* Expanded Dropdown */} + {isExpanded && ( +
+
+ RPC Providers + Strategy: {metadata.strategy} +
- {metadata.hasInconsistencies && ( -
- ⚠️ Responses differ between providers -
- )} + {metadata.hasInconsistencies && ( +
⚠️ Responses differ between providers
+ )} -
- {metadata.responses.map((response, idx) => { - const isSelected = selectedProvider === response.url; - const urlDisplay = truncateUrl(response.url); +
+ {metadata.responses.map((response, idx) => { + const isSelected = selectedProvider === response.url; + const urlDisplay = truncateUrl(response.url); - return ( -
{ - if (response.status === "success") { - onProviderSelect(response.url); - setIsExpanded(false); - } - }} - > -
- #{idx + 1} - - {urlDisplay} - - - {response.status === "success" ? "βœ“" : "βœ—"} - -
+ return ( + // biome-ignore lint/a11y/noStaticElementInteractions: + // biome-ignore lint/a11y/useKeyWithClickEvents: +
{ + if (response.status === "success") { + onProviderSelect(response.url); + setIsExpanded(false); + } + }} + > +
+ #{idx + 1} + + {urlDisplay} + + + {response.status === "success" ? "βœ“" : "βœ—"} + +
- {response.status === "error" && ( -
- {response.error} -
- )} + {response.status === "error" && ( +
{response.error}
+ )} - {isSelected && ( -
Selected
- )} -
- ); - })} -
-
- )} -
- ); + {isSelected &&
Selected
} +
+ ); + })} +
+
+ )} +
+ ); } /** * Truncate URL to show hostname only */ function truncateUrl(url: string): string { - try { - const urlObj = new URL(url); - const hostname = urlObj.hostname; - if (hostname.length > 30) { - return hostname.slice(0, 15) + "..." + hostname.slice(-12); - } - return hostname; - } catch { - return url.length > 30 ? url.slice(0, 15) + "..." + url.slice(-12) : url; - } + try { + const urlObj = new URL(url); + const hostname = urlObj.hostname; + if (hostname.length > 30) { + return hostname.slice(0, 15) + "..." + hostname.slice(-12); + } + return hostname; + } catch { + return url.length > 30 ? url.slice(0, 15) + "..." + url.slice(-12) : url; + } } export default RPCIndicator; diff --git a/src/components/common/SearchBox.tsx b/src/components/common/SearchBox.tsx index 6272432..efc6894 100644 --- a/src/components/common/SearchBox.tsx +++ b/src/components/common/SearchBox.tsx @@ -1,56 +1,54 @@ -import React, { useState } from "react"; +import type React from "react"; +import { useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; const SearchBox = () => { - const [searchTerm, setSearchTerm] = useState(""); - const navigate = useNavigate(); - const location = useLocation(); + const [searchTerm, setSearchTerm] = useState(""); + const navigate = useNavigate(); + const location = useLocation(); - // Extract chainId from the pathname (e.g., /1/blocks -> 1) - const pathSegments = location.pathname.split("/").filter(Boolean); - const chainId = - pathSegments[0] && !isNaN(Number(pathSegments[0])) - ? pathSegments[0] - : undefined; + // Extract chainId from the pathname (e.g., /1/blocks -> 1) + const pathSegments = location.pathname.split("/").filter(Boolean); + const chainId = pathSegments[0] && !isNaN(Number(pathSegments[0])) ? pathSegments[0] : undefined; - const handleSearch = (e: React.FormEvent) => { - e.preventDefault(); - if (!searchTerm.trim()) return; + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + if (!searchTerm.trim()) return; - // Basic routing logic placeholder - // In a real app, we would detect the type of input (address, tx, block) - // For now, we'll just log it or maybe navigate to a search result page if it existed. - // Since the user just asked for the UI, we'll keep the logic minimal but functional enough to show interaction. - console.log("Searching for:", searchTerm); + // Basic routing logic placeholder + // In a real app, we would detect the type of input (address, tx, block) + // For now, we'll just log it or maybe navigate to a search result page if it existed. + // Since the user just asked for the UI, we'll keep the logic minimal but functional enough to show interaction. + console.log("Searching for:", searchTerm); - // Example logic: - if (searchTerm.startsWith("0x")) { - if (searchTerm.length === 42) { - navigate(`/${chainId}/address/${searchTerm}`); - } else if (searchTerm.length === 66) { - navigate(`/${chainId}/tx/${searchTerm}`); - } - } else if (!isNaN(Number(searchTerm))) { - navigate(`/${chainId}/block/${searchTerm}`); - } - }; + // Example logic: + if (searchTerm.startsWith("0x")) { + if (searchTerm.length === 42) { + navigate(`/${chainId}/address/${searchTerm}`); + } else if (searchTerm.length === 66) { + navigate(`/${chainId}/tx/${searchTerm}`); + } + } else if (!isNaN(Number(searchTerm))) { + navigate(`/${chainId}/block/${searchTerm}`); + } + }; - return ( -
-
- setSearchTerm(e.target.value)} - /> - -
-
- ); + return ( +
+
+ setSearchTerm(e.target.value)} + /> + +
+
+ ); }; export default SearchBox; diff --git a/src/components/common/TransactionDisplay.tsx b/src/components/common/TransactionDisplay.tsx index 260b6c3..5cbc2a3 100644 --- a/src/components/common/TransactionDisplay.tsx +++ b/src/components/common/TransactionDisplay.tsx @@ -1,771 +1,672 @@ -import React, { - useState, - useEffect, - useRef, - useMemo, - useCallback, -} from "react"; +import React, { useState, useEffect, useRef, useMemo, useCallback } from "react"; import { Link } from "react-router-dom"; import type { - Transaction, - TransactionArbitrum, - TransactionReceiptArbitrum, - TransactionReceiptOptimism, - RPCMetadata, + Transaction, + TransactionArbitrum, + TransactionReceiptArbitrum, + TransactionReceiptOptimism, + RPCMetadata, } from "../../types"; import LongString from "./LongString"; -import { DataService } from "../../services/DataService"; -import { TraceResult } from "../../services/EVM/L1/fetchers/trace"; +import type { DataService } from "../../services/DataService"; +import type { TraceResult } from "../../services/EVM/L1/fetchers/trace"; import { - decodeEventLog, - DecodedEvent, - formatDecodedValue, - getEventTypeColor, + decodeEventLog, + type DecodedEvent, + formatDecodedValue, + getEventTypeColor, } from "../../utils/eventDecoder"; import { RPCIndicator } from "./RPCIndicator"; interface TransactionDisplayProps { - transaction: Transaction | TransactionArbitrum; - chainId?: string; - currentBlockNumber?: number; - dataService?: DataService; - metadata?: RPCMetadata; - selectedProvider?: string | null; - onProviderSelect?: (provider: string) => void; + transaction: Transaction | TransactionArbitrum; + chainId?: string; + currentBlockNumber?: number; + dataService?: DataService; + metadata?: RPCMetadata; + selectedProvider?: string | null; + onProviderSelect?: (provider: string) => void; } const TransactionDisplay: React.FC = React.memo( - ({ - transaction, - chainId, - currentBlockNumber, - dataService, - metadata, - selectedProvider, - onProviderSelect, - }) => { - const [showRawData, setShowRawData] = useState(false); - const [showLogs, setShowLogs] = useState(false); - const [showTrace, setShowTrace] = useState(false); - const [traceData, setTraceData] = useState(null); - const [callTrace, setCallTrace] = useState(null); - const [loadingTrace, setLoadingTrace] = useState(false); - const [copiedField, setCopiedField] = useState(null); - const copyTimeoutRef = useRef | null>(null); - - // Check if trace is available (localhost only) - const isTraceAvailable = dataService?.isTraceAvailable() || false; - - // Load trace data when trace section is expanded - useEffect(() => { - if ( - showTrace && - isTraceAvailable && - dataService && - !traceData && - !callTrace - ) { - setLoadingTrace(true); - Promise.all([ - dataService.getTransactionTrace(transaction.hash), - dataService.getCallTrace(transaction.hash), - ]) - .then(([trace, call]) => { - setTraceData(trace); - setCallTrace(call); - }) - .catch((err) => console.error("Error loading trace:", err)) - .finally(() => setLoadingTrace(false)); - } - }, [ - showTrace, - isTraceAvailable, - dataService, - transaction.hash, - traceData, - callTrace, - ]); - - useEffect(() => { - return () => { - if (copyTimeoutRef.current) { - clearTimeout(copyTimeoutRef.current); - } - }; - }, []); - - // Check if this is an Arbitrum transaction - const isArbitrumTx = useCallback( - (tx: Transaction | TransactionArbitrum): tx is TransactionArbitrum => { - return "requestId" in tx; - }, - [], - ); - - // Check if receipt is Arbitrum receipt - const isArbitrumReceipt = useCallback( - (receipt: any): receipt is TransactionReceiptArbitrum => { - return receipt && "l1BlockNumber" in receipt; - }, - [], - ); - - // Check if receipt is Optimism receipt - const isOptimismReceipt = useCallback( - (receipt: any): receipt is TransactionReceiptOptimism => { - return receipt && "l1Fee" in receipt; - }, - [], - ); - - const truncate = useCallback((str: string, start = 6, end = 4) => { - if (!str) return ""; - if (str.length <= start + end) return str; - return `${str.slice(0, start)}...${str.slice(-end)}`; - }, []); - - const formatValue = useCallback((value: string) => { - try { - const eth = Number(value) / 1e18; - return `${eth.toFixed(6)} ETH`; - } catch (e) { - return value; - } - }, []); - - const formatGwei = useCallback((value: string) => { - try { - const gwei = Number(value) / 1e9; - return `${gwei.toFixed(2)} Gwei`; - } catch (e) { - return value; - } - }, []); - - const parseTimestampToMs = useCallback((timestamp?: string) => { - if (!timestamp) return null; - const parsed = parseInt(timestamp, timestamp.startsWith("0x") ? 16 : 10); - if (Number.isNaN(parsed)) return null; - return parsed * 1000; - }, []); - - const formatAbsoluteTimestamp = useCallback((timestampMs: number) => { - try { - return new Intl.DateTimeFormat(undefined, { - year: "numeric", - month: "short", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - timeZoneName: "short", - }).format(new Date(timestampMs)); - } catch (error) { - return new Date(timestampMs).toISOString(); - } - }, []); - - const formatTimeAgo = useCallback((timestampMs: number) => { - const diffMs = Date.now() - timestampMs; - const diffSeconds = Math.floor(Math.abs(diffMs) / 1000); - if (diffSeconds < 5) { - return diffMs >= 0 ? "just now" : "in a few seconds"; - } - - const units = [ - { label: "day", seconds: 60 * 60 * 24 }, - { label: "hour", seconds: 60 * 60 }, - { label: "minute", seconds: 60 }, - ]; - - for (const unit of units) { - if (diffSeconds >= unit.seconds) { - const value = Math.floor(diffSeconds / unit.seconds); - const plural = value === 1 ? "" : "s"; - return diffMs >= 0 - ? `${value} ${unit.label}${plural} ago` - : `in ${value} ${unit.label}${plural}`; - } - } - - return diffMs >= 0 - ? `${diffSeconds} second${diffSeconds === 1 ? "" : "s"} ago` - : `in ${diffSeconds} second${diffSeconds === 1 ? "" : "s"}`; - }, []); - - const timestampMs = useMemo( - () => parseTimestampToMs(transaction.timestamp), - [parseTimestampToMs, transaction.timestamp], - ); - const formattedTimestamp = useMemo( - () => (timestampMs ? formatAbsoluteTimestamp(timestampMs) : null), - [timestampMs, formatAbsoluteTimestamp], - ); - const timestampAge = useMemo( - () => (timestampMs ? formatTimeAgo(timestampMs) : null), - [timestampMs, formatTimeAgo], - ); - - const getStatusBadge = useCallback((status?: string) => { - if (!status) return null; - const isSuccess = status === "0x1" || status === "1"; - return ( - - {isSuccess ? "Success" : "Failed"} - - ); - }, []); - - const confirmations = useMemo( - () => - currentBlockNumber - ? currentBlockNumber - Number(transaction.blockNumber) - : null, - [currentBlockNumber, transaction.blockNumber], - ); - - return ( -
-
- Transaction Details - {metadata && selectedProvider !== undefined && onProviderSelect && ( - - )} -
- - {/* Row-based layout like Etherscan */} -
- {/* Transaction Hash */} -
- Transaction Hash: - - - -
- - {/* Status */} -
- Status: - - {getStatusBadge(transaction.receipt?.status)} - -
- - {/* Block */} -
- Block: - - {chainId ? ( - - {Number(transaction.blockNumber).toLocaleString()} - - ) : ( - Number(transaction.blockNumber).toLocaleString() - )} - {confirmations !== null && ( - - {confirmations > 100 - ? "+100" - : confirmations.toLocaleString()}{" "} - Block Confirmations - - )} - -
- - {/* Timestamp */} - {formattedTimestamp && ( -
- Timestamp: - - {timestampAge && {timestampAge}} - - ({formattedTimestamp}) - - -
- )} - - {/* From */} -
- From: - - {chainId ? ( - - {transaction.from} - - ) : ( - transaction.from - )} - -
- - {/* To */} -
- - {transaction.to ? "To:" : "Interacted With:"} - - - {transaction.to ? ( - chainId ? ( - - {transaction.to} - - ) : ( - transaction.to - ) - ) : ( - - Contract Creation - - )} - -
- - {/* Contract Address (if created) */} - {transaction.receipt?.contractAddress && ( -
- Contract Created: - - {chainId ? ( - - {transaction.receipt.contractAddress} - - ) : ( - transaction.receipt.contractAddress - )} - -
- )} - - {/* Value */} -
- Value: - - {formatValue(transaction.value)} - -
- - {/* Transaction Fee */} -
- Transaction Fee: - - {transaction.receipt - ? formatValue( - ( - BigInt(transaction.receipt.gasUsed) * - BigInt(transaction.receipt.effectiveGasPrice) - ).toString(), - ) - : "Pending"} - -
- - {/* Gas Price */} -
- Gas Price: - {formatGwei(transaction.gasPrice)} -
- - {/* Gas Limit & Usage */} -
- Gas Limit & Usage: - - {Number(transaction.gas).toLocaleString()} - {transaction.receipt && ( - <> - {" | "} - {Number(transaction.receipt.gasUsed).toLocaleString()} - - ( - {( - (Number(transaction.receipt.gasUsed) / - Number(transaction.gas)) * - 100 - ).toFixed(1)} - %) - - - )} - -
- - {/* Effective Gas Price (if different from gas price) */} - {transaction.receipt && - transaction.receipt.effectiveGasPrice !== transaction.gasPrice && ( -
- Effective Gas Price: - - {formatGwei(transaction.receipt.effectiveGasPrice)} - -
- )} - - {/* Arbitrum-specific fields */} - {isArbitrumTx(transaction) && - transaction.receipt && - isArbitrumReceipt(transaction.receipt) && ( - <> -
- L1 Block Number: - - {Number(transaction.receipt.l1BlockNumber).toLocaleString()} - -
-
- Gas Used for L1: - - {Number(transaction.receipt.gasUsedForL1).toLocaleString()} - -
- - )} - - {/* OP Stack fields (Optimism, Base) */} - {transaction.receipt && isOptimismReceipt(transaction.receipt) && ( - <> -
- L1 Fee: - - {formatValue(transaction.receipt.l1Fee)} - -
-
- L1 Gas Price: - - {formatGwei(transaction.receipt.l1GasPrice)} - -
-
- L1 Gas Used: - - {Number(transaction.receipt.l1GasUsed).toLocaleString()} - -
-
- L1 Fee Scalar: - - {transaction.receipt.l1FeeScalar} - -
- - )} - - {/* Other Attributes (Nonce, Index, Type) */} -
- Other Attributes: - - Nonce: {transaction.nonce} - - Position: {transaction.transactionIndex} - - Type: {transaction.type} - -
- - {/* Input Data */} -
- Input Data: - {transaction.data && transaction.data !== "0x" ? ( -
- {transaction.data} -
- ) : ( - 0x - )} -
-
- - {/* Event Logs Section - Always visible */} - {transaction.receipt && transaction.receipt.logs.length > 0 && ( -
-
- - Event Logs ({transaction.receipt.logs.length}) - -
-
- {transaction.receipt.logs.map((log: any, index: number) => { - const decoded: DecodedEvent | null = log.topics - ? decodeEventLog(log.topics, log.data || "0x") - : null; - - return ( -
-
{index}
-
- {/* Decoded Event Header */} - {decoded && ( -
- - {decoded.name} - - - {decoded.fullSignature} - -
- )} - - {/* Address */} -
- Address - - {chainId ? ( - - {log.address} - - ) : ( - log.address - )} - -
- - {/* Decoded Parameters */} - {decoded && decoded.params.length > 0 && ( -
- Decoded -
- {decoded.params.map((param, i) => ( -
- - {param.name} - - - ({param.type}) - - - {param.type === "address" && chainId ? ( - - {param.value} - - ) : ( - formatDecodedValue(param.value, param.type) - )} - - {param.indexed && ( - - indexed - - )} -
- ))} -
-
- )} - - {/* Raw Topics (collapsed if decoded) */} - {log.topics && log.topics.length > 0 && ( -
- - {decoded ? "Raw Topics" : "Topics"} - -
- {log.topics.map((topic: string, i: number) => ( -
- [{i}] - {topic} -
- ))} -
-
- )} - - {/* Raw Data */} - {log.data && log.data !== "0x" && ( -
- - {decoded ? "Raw Data" : "Data"} - -
- {log.data} -
-
- )} -
-
- ); - })} -
-
- )} - - {/* Debug Trace Section (Localhost Only) */} - {isTraceAvailable && ( -
- - - {showTrace && ( -
- {loadingTrace && ( -
Loading trace data...
- )} - - {/* Call Trace */} - {callTrace && ( -
-
Call Trace
-
-
- Type:{" "} - {callTrace.type} -
-
- From:{" "} - -
-
- To:{" "} - -
-
- Value:{" "} - {callTrace.value} -
-
- Gas: {callTrace.gas} -
-
- Gas Used:{" "} - {callTrace.gasUsed} -
- {callTrace.error && ( -
- Error:{" "} - {callTrace.error} -
- )} - {callTrace.calls && callTrace.calls.length > 0 && ( -
-
- Internal Calls ({callTrace.calls.length}): -
-
- {JSON.stringify(callTrace.calls, null, 2)} -
-
- )} -
-
- )} - - {/* Opcode Trace */} - {traceData && ( -
-
Execution Trace
-
-
- Total Gas Used:{" "} - {traceData.gas} -
-
- Failed:{" "} - {traceData.failed ? "Yes" : "No"} -
-
- Return Value:{" "} - -
-
- Opcodes Executed:{" "} - {traceData.structLogs.length} -
-
- -
- Opcode Execution Log: -
-
- {traceData.structLogs.slice(0, 100).map((log, index) => ( -
-
- Step {index}: {log.op} -
-
- PC: {log.pc} | Gas: {log.gas} | Cost: {log.gasCost}{" "} - | Depth: {log.depth} -
- {log.stack && log.stack.length > 0 && ( -
- Stack: [{log.stack.slice(0, 3).join(", ")} - {log.stack.length > 3 ? "..." : ""}] -
- )} -
- ))} - {traceData.structLogs.length > 100 && ( -
- ... showing first 100 of {traceData.structLogs.length}{" "} - steps -
- )} -
-
- )} -
- )} -
- )} -
- ); - }, + ({ + transaction, + chainId, + currentBlockNumber, + dataService, + metadata, + selectedProvider, + onProviderSelect, + }) => { + const [showRawData, setShowRawData] = useState(false); + const [showLogs, setShowLogs] = useState(false); + const [showTrace, setShowTrace] = useState(false); + const [traceData, setTraceData] = useState(null); + const [callTrace, setCallTrace] = useState(null); + const [loadingTrace, setLoadingTrace] = useState(false); + const [copiedField, setCopiedField] = useState(null); + const copyTimeoutRef = useRef | null>(null); + + // Check if trace is available (localhost only) + const isTraceAvailable = dataService?.isTraceAvailable() || false; + + // Load trace data when trace section is expanded + useEffect(() => { + if (showTrace && isTraceAvailable && dataService && !traceData && !callTrace) { + setLoadingTrace(true); + Promise.all([ + dataService.getTransactionTrace(transaction.hash), + dataService.getCallTrace(transaction.hash), + ]) + .then(([trace, call]) => { + setTraceData(trace); + setCallTrace(call); + }) + .catch((err) => console.error("Error loading trace:", err)) + .finally(() => setLoadingTrace(false)); + } + }, [showTrace, isTraceAvailable, dataService, transaction.hash, traceData, callTrace]); + + useEffect(() => { + return () => { + if (copyTimeoutRef.current) { + clearTimeout(copyTimeoutRef.current); + } + }; + }, []); + + // Check if this is an Arbitrum transaction + const isArbitrumTx = useCallback( + (tx: Transaction | TransactionArbitrum): tx is TransactionArbitrum => { + return "requestId" in tx; + }, + [], + ); + + // Check if receipt is Arbitrum receipt + const isArbitrumReceipt = useCallback((receipt: any): receipt is TransactionReceiptArbitrum => { + return receipt && "l1BlockNumber" in receipt; + }, []); + + // Check if receipt is Optimism receipt + const isOptimismReceipt = useCallback((receipt: any): receipt is TransactionReceiptOptimism => { + return receipt && "l1Fee" in receipt; + }, []); + + const truncate = useCallback((str: string, start = 6, end = 4) => { + if (!str) return ""; + if (str.length <= start + end) return str; + return `${str.slice(0, start)}...${str.slice(-end)}`; + }, []); + + const formatValue = useCallback((value: string) => { + try { + const eth = Number(value) / 1e18; + return `${eth.toFixed(6)} ETH`; + } catch (e) { + return value; + } + }, []); + + const formatGwei = useCallback((value: string) => { + try { + const gwei = Number(value) / 1e9; + return `${gwei.toFixed(2)} Gwei`; + } catch (e) { + return value; + } + }, []); + + const parseTimestampToMs = useCallback((timestamp?: string) => { + if (!timestamp) return null; + const parsed = parseInt(timestamp, timestamp.startsWith("0x") ? 16 : 10); + if (Number.isNaN(parsed)) return null; + return parsed * 1000; + }, []); + + const formatAbsoluteTimestamp = useCallback((timestampMs: number) => { + try { + return new Intl.DateTimeFormat(undefined, { + year: "numeric", + month: "short", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZoneName: "short", + }).format(new Date(timestampMs)); + } catch (error) { + return new Date(timestampMs).toISOString(); + } + }, []); + + const formatTimeAgo = useCallback((timestampMs: number) => { + const diffMs = Date.now() - timestampMs; + const diffSeconds = Math.floor(Math.abs(diffMs) / 1000); + if (diffSeconds < 5) { + return diffMs >= 0 ? "just now" : "in a few seconds"; + } + + const units = [ + { label: "day", seconds: 60 * 60 * 24 }, + { label: "hour", seconds: 60 * 60 }, + { label: "minute", seconds: 60 }, + ]; + + for (const unit of units) { + if (diffSeconds >= unit.seconds) { + const value = Math.floor(diffSeconds / unit.seconds); + const plural = value === 1 ? "" : "s"; + return diffMs >= 0 + ? `${value} ${unit.label}${plural} ago` + : `in ${value} ${unit.label}${plural}`; + } + } + + return diffMs >= 0 + ? `${diffSeconds} second${diffSeconds === 1 ? "" : "s"} ago` + : `in ${diffSeconds} second${diffSeconds === 1 ? "" : "s"}`; + }, []); + + const timestampMs = useMemo( + () => parseTimestampToMs(transaction.timestamp), + [parseTimestampToMs, transaction.timestamp], + ); + const formattedTimestamp = useMemo( + () => (timestampMs ? formatAbsoluteTimestamp(timestampMs) : null), + [timestampMs, formatAbsoluteTimestamp], + ); + const timestampAge = useMemo( + () => (timestampMs ? formatTimeAgo(timestampMs) : null), + [timestampMs, formatTimeAgo], + ); + + const getStatusBadge = useCallback((status?: string) => { + if (!status) return null; + const isSuccess = status === "0x1" || status === "1"; + return ( + + {isSuccess ? "Success" : "Failed"} + + ); + }, []); + + const confirmations = useMemo( + () => (currentBlockNumber ? currentBlockNumber - Number(transaction.blockNumber) : null), + [currentBlockNumber, transaction.blockNumber], + ); + + return ( +
+
+ Transaction Details + {metadata && selectedProvider !== undefined && onProviderSelect && ( + + )} +
+ + {/* Row-based layout like Etherscan */} +
+ {/* Transaction Hash */} +
+ Transaction Hash: + + + +
+ + {/* Status */} +
+ Status: + {getStatusBadge(transaction.receipt?.status)} +
+ + {/* Block */} +
+ Block: + + {chainId ? ( + + {Number(transaction.blockNumber).toLocaleString()} + + ) : ( + Number(transaction.blockNumber).toLocaleString() + )} + {confirmations !== null && ( + + {confirmations > 100 ? "+100" : confirmations.toLocaleString()} Block + Confirmations + + )} + +
+ + {/* Timestamp */} + {formattedTimestamp && ( +
+ Timestamp: + + {timestampAge && {timestampAge}} + ({formattedTimestamp}) + +
+ )} + + {/* From */} +
+ From: + + {chainId ? ( + + {transaction.from} + + ) : ( + transaction.from + )} + +
+ + {/* To */} +
+ {transaction.to ? "To:" : "Interacted With:"} + + {transaction.to ? ( + chainId ? ( + + {transaction.to} + + ) : ( + transaction.to + ) + ) : ( + Contract Creation + )} + +
+ + {/* Contract Address (if created) */} + {transaction.receipt?.contractAddress && ( +
+ Contract Created: + + {chainId ? ( + + {transaction.receipt.contractAddress} + + ) : ( + transaction.receipt.contractAddress + )} + +
+ )} + + {/* Value */} +
+ Value: + {formatValue(transaction.value)} +
+ + {/* Transaction Fee */} +
+ Transaction Fee: + + {transaction.receipt + ? formatValue( + ( + BigInt(transaction.receipt.gasUsed) * + BigInt(transaction.receipt.effectiveGasPrice) + ).toString(), + ) + : "Pending"} + +
+ + {/* Gas Price */} +
+ Gas Price: + {formatGwei(transaction.gasPrice)} +
+ + {/* Gas Limit & Usage */} +
+ Gas Limit & Usage: + + {Number(transaction.gas).toLocaleString()} + {transaction.receipt && ( + <> + {" | "} + {Number(transaction.receipt.gasUsed).toLocaleString()} + + ( + {( + (Number(transaction.receipt.gasUsed) / Number(transaction.gas)) * + 100 + ).toFixed(1)} + %) + + + )} + +
+ + {/* Effective Gas Price (if different from gas price) */} + {transaction.receipt && + transaction.receipt.effectiveGasPrice !== transaction.gasPrice && ( +
+ Effective Gas Price: + + {formatGwei(transaction.receipt.effectiveGasPrice)} + +
+ )} + + {/* Arbitrum-specific fields */} + {isArbitrumTx(transaction) && + transaction.receipt && + isArbitrumReceipt(transaction.receipt) && ( + <> +
+ L1 Block Number: + + {Number(transaction.receipt.l1BlockNumber).toLocaleString()} + +
+
+ Gas Used for L1: + + {Number(transaction.receipt.gasUsedForL1).toLocaleString()} + +
+ + )} + + {/* OP Stack fields (Optimism, Base) */} + {transaction.receipt && isOptimismReceipt(transaction.receipt) && ( + <> +
+ L1 Fee: + {formatValue(transaction.receipt.l1Fee)} +
+
+ L1 Gas Price: + {formatGwei(transaction.receipt.l1GasPrice)} +
+
+ L1 Gas Used: + + {Number(transaction.receipt.l1GasUsed).toLocaleString()} + +
+
+ L1 Fee Scalar: + {transaction.receipt.l1FeeScalar} +
+ + )} + + {/* Other Attributes (Nonce, Index, Type) */} +
+ Other Attributes: + + Nonce: {transaction.nonce} + Position: {transaction.transactionIndex} + Type: {transaction.type} + +
+ + {/* Input Data */} +
+ Input Data: + {transaction.data && transaction.data !== "0x" ? ( +
+ {transaction.data} +
+ ) : ( + 0x + )} +
+
+ + {/* Event Logs Section - Always visible */} + {transaction.receipt && transaction.receipt.logs.length > 0 && ( +
+
+ + Event Logs ({transaction.receipt.logs.length}) + +
+
+ {transaction.receipt.logs.map((log: any, index: number) => { + const decoded: DecodedEvent | null = log.topics + ? decodeEventLog(log.topics, log.data || "0x") + : null; + + return ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+
{index}
+
+ {/* Decoded Event Header */} + {decoded && ( +
+ + {decoded.name} + + + {decoded.fullSignature} + +
+ )} + + {/* Address */} +
+ Address + + {chainId ? ( + + {log.address} + + ) : ( + log.address + )} + +
+ + {/* Decoded Parameters */} + {decoded && decoded.params.length > 0 && ( +
+ Decoded +
+ {decoded.params.map((param, i) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+ {param.name} + ({param.type}) + + {param.type === "address" && chainId ? ( + + {param.value} + + ) : ( + formatDecodedValue(param.value, param.type) + )} + + {param.indexed && indexed} +
+ ))} +
+
+ )} + + {/* Raw Topics (collapsed if decoded) */} + {log.topics && log.topics.length > 0 && ( +
+ {decoded ? "Raw Topics" : "Topics"} +
+ {log.topics.map((topic: string, i: number) => ( +
+ [{i}] + {topic} +
+ ))} +
+
+ )} + + {/* Raw Data */} + {log.data && log.data !== "0x" && ( +
+ {decoded ? "Raw Data" : "Data"} +
+ {log.data} +
+
+ )} +
+
+ ); + })} +
+
+ )} + + {/* Debug Trace Section (Localhost Only) */} + {isTraceAvailable && ( +
+ {/** biome-ignore lint/a11y/useButtonType: */} + + + {showTrace && ( +
+ {loadingTrace &&
Loading trace data...
} + + {/* Call Trace */} + {callTrace && ( +
+
Call Trace
+
+
+ Type: {callTrace.type} +
+
+ From:{" "} + +
+
+ To:{" "} + +
+
+ Value: {callTrace.value} +
+
+ Gas: {callTrace.gas} +
+
+ Gas Used: {callTrace.gasUsed} +
+ {callTrace.error && ( +
+ Error: {callTrace.error} +
+ )} + {callTrace.calls && callTrace.calls.length > 0 && ( +
+
+ Internal Calls ({callTrace.calls.length}): +
+
+ {JSON.stringify(callTrace.calls, null, 2)} +
+
+ )} +
+
+ )} + + {/* Opcode Trace */} + {traceData && ( +
+
Execution Trace
+
+
+ Total Gas Used: {traceData.gas} +
+
+ Failed: {traceData.failed ? "Yes" : "No"} +
+
+ Return Value:{" "} + +
+
+ Opcodes Executed:{" "} + {traceData.structLogs.length} +
+
+ +
Opcode Execution Log:
+
+ {traceData.structLogs.slice(0, 100).map((log, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+
+ Step {index}: {log.op} +
+
+ PC: {log.pc} | Gas: {log.gas} | Cost: {log.gasCost} | Depth: {log.depth} +
+ {log.stack && log.stack.length > 0 && ( +
+ Stack: [{log.stack.slice(0, 3).join(", ")} + {log.stack.length > 3 ? "..." : ""}] +
+ )} +
+ ))} + {traceData.structLogs.length > 100 && ( +
+ ... showing first 100 of {traceData.structLogs.length} steps +
+ )} +
+
+ )} +
+ )} +
+ )} +
+ ); + }, ); TransactionDisplay.displayName = "TransactionDisplay"; diff --git a/src/components/common/TransactionReceiptDisplay.tsx b/src/components/common/TransactionReceiptDisplay.tsx index c926c6e..e41fc8e 100644 --- a/src/components/common/TransactionReceiptDisplay.tsx +++ b/src/components/common/TransactionReceiptDisplay.tsx @@ -1,80 +1,70 @@ -import React from "react"; -import { TransactionReceipt } from "../../types"; +import type React from "react"; +import type { TransactionReceipt } from "../../types"; interface TransactionReceiptDisplayProps { - receipt: TransactionReceipt; + receipt: TransactionReceipt; } -const TransactionReceiptDisplay: React.FC = ({ - receipt, -}) => { - const truncate = (str: string, start = 6, end = 4) => { - if (!str) return ""; - if (str.length <= start + end) return str; - return `${str.slice(0, start)}...${str.slice(-end)}`; - }; +const TransactionReceiptDisplay: React.FC = ({ receipt }) => { + const truncate = (str: string, start = 6, end = 4) => { + if (!str) return ""; + if (str.length <= start + end) return str; + return `${str.slice(0, start)}...${str.slice(-end)}`; + }; - const getStatusText = (status: string) => { - return status === "1" || status === "0x1" ? "Success" : "Failed"; - }; + const getStatusText = (status: string) => { + return status === "1" || status === "0x1" ? "Success" : "Failed"; + }; - return ( -
-
- Receipt: - - {truncate(receipt.transactionHash, 8, 6)} - -
+ return ( +
+
+ Receipt: + {truncate(receipt.transactionHash, 8, 6)} +
-
-
- Status - {getStatusText(receipt.status)} -
+
+
+ Status + {getStatusText(receipt.status)} +
-
- Block Number - {receipt.blockNumber} -
+
+ Block Number + {receipt.blockNumber} +
-
- From - - {truncate(receipt.from)} - -
+
+ From + + {truncate(receipt.from)} + +
-
- To - - {truncate(receipt.to)} - -
+
+ To + + {truncate(receipt.to)} + +
-
- Gas Used - - {Number(receipt.gasUsed).toLocaleString()} - -
+
+ Gas Used + {Number(receipt.gasUsed).toLocaleString()} +
-
- Cumulative Gas Used - - {Number(receipt.cumulativeGasUsed).toLocaleString()} - -
+
+ Cumulative Gas Used + {Number(receipt.cumulativeGasUsed).toLocaleString()} +
-
- Contract Address - - {receipt.contractAddress || "N/A"} - -
-
-
- ); +
+ Contract Address + {receipt.contractAddress || "N/A"} +
+
+
+ ); }; export default TransactionReceiptDisplay; diff --git a/src/components/common/VersionWarningIcon.tsx b/src/components/common/VersionWarningIcon.tsx index 4969090..6213e27 100644 --- a/src/components/common/VersionWarningIcon.tsx +++ b/src/components/common/VersionWarningIcon.tsx @@ -1,58 +1,57 @@ -import React, { useState, useMemo } from "react"; +import type React from "react"; +import { useState, useMemo } from "react"; import { ENVIRONMENT } from "../../utils/constants"; interface VersionWarningIconProps { - readonly className?: string; + readonly className?: string; } // Constants outside component to avoid recreating const TOOLTIP_TEXT = "This is not a production verified version"; const ICON_COLORS = { - development: "#ef4444", - staging: "#f59e0b", - default: "#6b7280" + development: "#ef4444", + staging: "#f59e0b", + default: "#6b7280", } as const; const VersionWarningIcon: React.FC = ({ className = "" }) => { - const [showTooltip, setShowTooltip] = useState(false); + const [showTooltip, setShowTooltip] = useState(false); - // Memoize color calculation - const iconColor = useMemo(() => { - return ICON_COLORS[ENVIRONMENT as keyof typeof ICON_COLORS] || ICON_COLORS.default; - }, []); + // Memoize color calculation + const iconColor = useMemo(() => { + return ICON_COLORS[ENVIRONMENT as keyof typeof ICON_COLORS] || ICON_COLORS.default; + }, []); - if (ENVIRONMENT === "production") { - return null; - } + if (ENVIRONMENT === "production") { + return null; + } - return ( -
setShowTooltip(true)} - onMouseLeave={() => setShowTooltip(false)} - > - - - - {showTooltip && ( -
- {TOOLTIP_TEXT} -
- )} -
- ); + return ( + // biome-ignore lint/a11y/noStaticElementInteractions: +
setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > + {/** biome-ignore lint/a11y/noSvgWithoutTitle: */} + + + + {showTooltip &&
{TOOLTIP_TEXT}
} +
+ ); }; -export default VersionWarningIcon; \ No newline at end of file +export default VersionWarningIcon; diff --git a/src/components/common/modal/BaseModal.tsx b/src/components/common/modal/BaseModal.tsx index 7316c03..2d7d79a 100644 --- a/src/components/common/modal/BaseModal.tsx +++ b/src/components/common/modal/BaseModal.tsx @@ -1,65 +1,71 @@ -import React, { ReactNode } from "react"; +import type React from "react"; +import type { ReactNode } from "react"; import "../../../styles/styles.css"; export interface BaseModalProps { - isOpen: boolean; - onClose: () => void; - title: string; - children: ReactNode; - isLoading?: boolean; - size?: "sm" | "md" | "lg"; - closeOnOverlayClick?: boolean; + isOpen: boolean; + onClose: () => void; + title: string; + children: ReactNode; + isLoading?: boolean; + size?: "sm" | "md" | "lg"; + closeOnOverlayClick?: boolean; } export default function BaseModal({ - isOpen, - onClose, - title, - children, - isLoading = false, - size = "md", - closeOnOverlayClick = true, + isOpen, + onClose, + title, + children, + isLoading = false, + size = "md", + closeOnOverlayClick = true, }: BaseModalProps) { - if (!isOpen) return null; + if (!isOpen) return null; - const handleOverlayClick = (e: React.MouseEvent) => { - if (closeOnOverlayClick && !isLoading) { - onClose(); - } - }; + const handleOverlayClick = (e: React.MouseEvent) => { + if (closeOnOverlayClick && !isLoading) { + onClose(); + } + }; - const handleContentClick = (e: React.MouseEvent) => { - e.stopPropagation(); - }; + const handleContentClick = (e: React.MouseEvent) => { + e.stopPropagation(); + }; - const getSizeClass = () => { - switch (size) { - case "sm": - return "modal-sm"; - case "lg": - return "modal-lg"; - default: - return ""; - } - }; + const getSizeClass = () => { + switch (size) { + case "sm": + return "modal-sm"; + case "lg": + return "modal-lg"; + default: + return ""; + } + }; - return ( -
-
-
-

{title}

- -
+ return ( + // biome-ignore lint/a11y/noStaticElementInteractions: + // biome-ignore lint/a11y/useKeyWithClickEvents: +
+ {/** biome-ignore lint/a11y/noStaticElementInteractions: */} + {/** biome-ignore lint/a11y/useKeyWithClickEvents: */} +
+
+

{title}

+ {/** biome-ignore lint/a11y/useButtonType: */} + +
-
{children}
-
-
- ); +
{children}
+
+
+ ); } diff --git a/src/components/devtools/ContractsSection.tsx b/src/components/devtools/ContractsSection.tsx index a139b3c..337e7f5 100644 --- a/src/components/devtools/ContractsSection.tsx +++ b/src/components/devtools/ContractsSection.tsx @@ -1,541 +1,572 @@ -import React, { useState } from "react"; +import type React from "react"; +import { useState } from "react"; const NETWORKS: Record = { - 1: { name: "Ethereum Mainnet" }, - 10: { name: "Optimism" }, - 42161: { name: "Arbitrum One" }, - 8453: { name: "Base" }, - 137: { name: "Polygon" }, - 11155111: { name: "Sepolia" }, - 84532: { name: "Base Sepolia" }, + 1: { name: "Ethereum Mainnet" }, + 10: { name: "Optimism" }, + 42161: { name: "Arbitrum One" }, + 8453: { name: "Base" }, + 137: { name: "Polygon" }, + 11155111: { name: "Sepolia" }, + 84532: { name: "Base Sepolia" }, }; const SOURCIFY_API = "https://sourcify.dev/server"; const ContractsSection: React.FC = () => { - // Standard JSON Verification - const [showStandardVerify, setShowStandardVerify] = useState(true); - const [stdChainId, setStdChainId] = useState(1); - const [stdAddress, setStdAddress] = useState(""); - const [stdContractName, setStdContractName] = useState(""); - const [stdSources, setStdSources] = useState(JSON.stringify({ - "MyContract.sol": { - content: "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract MyContract {\n uint256 public value;\n \n constructor(uint256 _value) {\n value = _value;\n }\n}" - } - }, null, 2)); - const [stdSettings, setStdSettings] = useState(JSON.stringify({ - optimizer: { - enabled: true, - runs: 200 - }, - evmVersion: "paris" - }, null, 2)); - const [stdVerifying, setStdVerifying] = useState(false); - const [stdResult, setStdResult] = useState(null); - const [stdError, setStdError] = useState(null); - - // Metadata Verification - const [showMetadataVerify, setShowMetadataVerify] = useState(false); - const [metaChainId, setMetaChainId] = useState(1); - const [metaAddress, setMetaAddress] = useState(""); - const [metadataJson, setMetadataJson] = useState(""); - const [metaVerifying, setMetaVerifying] = useState(false); - const [metaResult, setMetaResult] = useState(null); - const [metaError, setMetaError] = useState(null); - - // Etherscan Import - const [showEtherscanImport, setShowEtherscanImport] = useState(false); - const [etherscanChainId, setEtherscanChainId] = useState(1); - const [etherscanAddress, setEtherscanAddress] = useState(""); - const [etherscanApiKey, setEtherscanApiKey] = useState(""); - const [etherscanImporting, setEtherscanImporting] = useState(false); - const [etherscanResult, setEtherscanResult] = useState(null); - const [etherscanError, setEtherscanError] = useState(null); - - // Similarity Verification - const [showSimilarityVerify, setShowSimilarityVerify] = useState(false); - const [simChainId, setSimChainId] = useState(1); - const [simAddress, setSimAddress] = useState(""); - const [simVerifying, setSimVerifying] = useState(false); - const [simResult, setSimResult] = useState(null); - const [simError, setSimError] = useState(null); - - // Standard JSON Verification - const verifyStandardJson = async () => { - setStdVerifying(true); - setStdError(null); - setStdResult(null); - - try { - if (!stdAddress || !stdContractName) { - throw new Error("Address and contract name are required"); - } - - const sources = JSON.parse(stdSources); - const settings = JSON.parse(stdSettings); - - const response = await fetch(`${SOURCIFY_API}/v2/verify/${stdChainId}/${stdAddress}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - contractName: stdContractName, - compilerVersion: "0.8.0", - sourceFiles: sources, - settings: settings, - }), - }); - - const data = await response.json(); - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}: ${response.statusText}`); - } - - setStdResult(data); - - // Poll for verification status if we got a verification ID - if (data.verificationId) { - pollVerificationStatus(data.verificationId, setStdResult, setStdError); - } - } catch (err: any) { - setStdError(err.message || String(err)); - } finally { - setStdVerifying(false); - } - }; - - // Metadata Verification - const verifyMetadata = async () => { - setMetaVerifying(true); - setMetaError(null); - setMetaResult(null); - - try { - if (!metaAddress || !metadataJson) { - throw new Error("Address and metadata JSON are required"); - } - - const metadata = JSON.parse(metadataJson); - - const response = await fetch(`${SOURCIFY_API}/v2/verify/metadata/${metaChainId}/${metaAddress}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - metadata: metadata, - }), - }); - - const data = await response.json(); - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}: ${response.statusText}`); - } - - setMetaResult(data); - - if (data.verificationId) { - pollVerificationStatus(data.verificationId, setMetaResult, setMetaError); - } - } catch (err: any) { - setMetaError(err.message || String(err)); - } finally { - setMetaVerifying(false); - } - }; - - // Etherscan Import - const importFromEtherscan = async () => { - setEtherscanImporting(true); - setEtherscanError(null); - setEtherscanResult(null); - - try { - if (!etherscanAddress) { - throw new Error("Address is required"); - } - - const url = new URL(`${SOURCIFY_API}/v2/verify/etherscan/${etherscanChainId}/${etherscanAddress}`); - if (etherscanApiKey) { - url.searchParams.append("apiKey", etherscanApiKey); - } - - const response = await fetch(url.toString(), { - method: "POST", - }); - - const data = await response.json(); - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}: ${response.statusText}`); - } - - setEtherscanResult(data); - - if (data.verificationId) { - pollVerificationStatus(data.verificationId, setEtherscanResult, setEtherscanError); - } - } catch (err: any) { - setEtherscanError(err.message || String(err)); - } finally { - setEtherscanImporting(false); - } - }; - - // Similarity Verification - const verifySimilarity = async () => { - setSimVerifying(true); - setSimError(null); - setSimResult(null); - - try { - if (!simAddress) { - throw new Error("Address is required"); - } - - const response = await fetch(`${SOURCIFY_API}/v2/verify/similarity/${simChainId}/${simAddress}`, { - method: "POST", - }); - - const data = await response.json(); - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}: ${response.statusText}`); - } - - setSimResult(data); - - if (data.verificationId) { - pollVerificationStatus(data.verificationId, setSimResult, setSimError); - } - } catch (err: any) { - setSimError(err.message || String(err)); - } finally { - setSimVerifying(false); - } - }; - - // Poll verification status - const pollVerificationStatus = async ( - verificationId: string, - setResult: (data: any) => void, - setError: (error: string) => void - ) => { - let attempts = 0; - const maxAttempts = 30; - const pollInterval = 2000; - - const poll = async () => { - try { - const response = await fetch(`${SOURCIFY_API}/v2/verify/${verificationId}`); - const data = await response.json(); - - if (data.status === "completed" || data.status === "failed") { - setResult(data); - return; - } - - attempts++; - if (attempts < maxAttempts) { - setTimeout(poll, pollInterval); - } else { - setError("Verification timed out. Check status manually."); - } - } catch (err: any) { - setError(err.message || String(err)); - } - }; - - poll(); - }; - - const renderResult = (result: any) => { - if (!result) return null; - return ( -
-
{JSON.stringify(result, null, 2)}
-
- ); - }; - - return ( -
- {/* Standard JSON Verification */} -
-
setShowStandardVerify(!showStandardVerify)} - > -

βœ… Verify Contract (Standard JSON)

- - {showStandardVerify ? "β–Ό" : "β–Ά"} - -
- {showStandardVerify && ( -
-
-
- - -
-
- - setStdAddress(e.target.value)} - /> -
-
- -
- - setStdContractName(e.target.value)} - /> -
- -
- -