diff --git a/.gitignore b/.gitignore index 4915261..f181d9e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ _types .eslintcache .DS_Store .vscode +coverage node_modules diff --git a/README.md b/README.md index 4e7ee9a..e04084f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ npm install @hemilabs/react-hooks | useAllowance | [useAllowance](./src/useAllowance.ts) | | useDebounce | [useDebounce](./src/useDebounce.ts) | | useEnsureConnectedTo | [useEnsureConnectedTo](./src/useEnsureConnectedTo.ts) | +| useEstimateApproveErc20Fees | [useEstimateApproveErc20Fees](./src/useEstimateApproveErc20Fees.ts) | +| useEstimateFees | [useEstimateFees](./src/useEstimateFees.ts) | | useNativeBalance | [useNativeBalance](./src/useNativeBalance.ts) | | useTokenBalance | [useTokenBalance](./src/useTokenBalance.ts) | | useUpdateNativeBalanceAfterReceipt | [useUpdateNativeBalanceAfterReceipt](./src/useUpdateNativeBalanceAfterReceipt.ts) | diff --git a/package.json b/package.json index 3210179..427e856 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hemilabs/react-hooks", - "version": "1.2.0", + "version": "1.3.0", "description": "Set of reusable hooks for Hemilabs apps with React and Typescript", "keywords": [ "hemilabs", @@ -35,14 +35,17 @@ "lint:fix": "eslint --cache . --fix", "prepare": "husky", "prepublishOnly": "npm run build", + "test": "vitest run", + "test:coverage": "vitest run --coverage", "tsc": "tsc" }, "devDependencies": { "@commitlint/cli": "^20.3.1", "@hemilabs/wallet-watch-asset": "^1.0.2", - "@tanstack/react-query": "5.90.20", + "@tanstack/react-query": "^5.90.20", "@tsconfig/vite-react": "^7.0.2", "@types/react": "^19.2.10", + "@vitest/coverage-v8": "^4.0.18", "@wagmi/core": "^2.19.5", "better-sort-github-actions": "^1.0.0", "better-sort-package-json": "^1.1.1", @@ -57,6 +60,7 @@ "typescript": "^5.9.3", "viem": "^2.45.0", "viem-erc20": "^2.1.0", + "vitest": "^4.0.18", "wagmi": "^2.19.5" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be99c45..eaba433 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: specifier: ^1.0.2 version: 1.0.2 "@tanstack/react-query": - specifier: 5.90.20 + specifier: ^5.90.20 version: 5.90.20(react@19.2.4) "@tsconfig/vite-react": specifier: ^7.0.2 @@ -22,6 +22,9 @@ importers: "@types/react": specifier: ^19.2.10 version: 19.2.10 + "@vitest/coverage-v8": + specifier: ^4.0.18 + version: 4.0.18(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2)) "@wagmi/core": specifier: ^2.19.5 version: 2.22.1(@tanstack/query-core@5.90.20)(@types/react@19.2.10)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) @@ -39,7 +42,7 @@ importers: version: 8.57.1 eslint-config-bloq: specifier: ^4.7.0 - version: 4.7.0(eslint@8.57.1)(typescript@5.9.3) + version: 4.7.0(@types/estree@1.0.8)(eslint@8.57.1)(typescript@5.9.3)(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2)) husky: specifier: ^9.1.7 version: 9.1.7 @@ -64,6 +67,9 @@ importers: viem-erc20: specifier: ^2.1.0 version: 2.1.0(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)) + vitest: + specifier: ^4.0.18 + version: 4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2) wagmi: specifier: ^2.19.5 version: 2.19.5(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@types/react@19.2.10)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@4.3.6) @@ -88,6 +94,13 @@ packages: } engines: { node: ">=6.9.0" } + "@babel/helper-string-parser@7.27.1": + resolution: + { + integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==, + } + engines: { node: ">=6.9.0" } + "@babel/helper-validator-identifier@7.28.5": resolution: { @@ -95,6 +108,14 @@ packages: } engines: { node: ">=6.9.0" } + "@babel/parser@7.29.0": + resolution: + { + integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==, + } + engines: { node: ">=6.0.0" } + hasBin: true + "@babel/runtime@7.28.6": resolution: { @@ -102,12 +123,26 @@ packages: } engines: { node: ">=6.9.0" } + "@babel/types@7.29.0": + resolution: + { + integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==, + } + engines: { node: ">=6.9.0" } + "@base-org/account@2.4.0": resolution: { integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==, } + "@bcoe/v8-coverage@1.0.2": + resolution: + { + integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==, + } + engines: { node: ">=18" } + "@coinbase/cdp-sdk@1.43.1": resolution: { @@ -273,6 +308,240 @@ packages: } engines: { node: ">=16" } + "@esbuild/aix-ppc64@0.27.3": + resolution: + { + integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [aix] + + "@esbuild/android-arm64@0.27.3": + resolution: + { + integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [android] + + "@esbuild/android-arm@0.27.3": + resolution: + { + integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [android] + + "@esbuild/android-x64@0.27.3": + resolution: + { + integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [android] + + "@esbuild/darwin-arm64@0.27.3": + resolution: + { + integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [darwin] + + "@esbuild/darwin-x64@0.27.3": + resolution: + { + integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [darwin] + + "@esbuild/freebsd-arm64@0.27.3": + resolution: + { + integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [freebsd] + + "@esbuild/freebsd-x64@0.27.3": + resolution: + { + integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [freebsd] + + "@esbuild/linux-arm64@0.27.3": + resolution: + { + integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [linux] + + "@esbuild/linux-arm@0.27.3": + resolution: + { + integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==, + } + engines: { node: ">=18" } + cpu: [arm] + os: [linux] + + "@esbuild/linux-ia32@0.27.3": + resolution: + { + integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [linux] + + "@esbuild/linux-loong64@0.27.3": + resolution: + { + integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==, + } + engines: { node: ">=18" } + cpu: [loong64] + os: [linux] + + "@esbuild/linux-mips64el@0.27.3": + resolution: + { + integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==, + } + engines: { node: ">=18" } + cpu: [mips64el] + os: [linux] + + "@esbuild/linux-ppc64@0.27.3": + resolution: + { + integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==, + } + engines: { node: ">=18" } + cpu: [ppc64] + os: [linux] + + "@esbuild/linux-riscv64@0.27.3": + resolution: + { + integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==, + } + engines: { node: ">=18" } + cpu: [riscv64] + os: [linux] + + "@esbuild/linux-s390x@0.27.3": + resolution: + { + integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==, + } + engines: { node: ">=18" } + cpu: [s390x] + os: [linux] + + "@esbuild/linux-x64@0.27.3": + resolution: + { + integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [linux] + + "@esbuild/netbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [netbsd] + + "@esbuild/netbsd-x64@0.27.3": + resolution: + { + integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [netbsd] + + "@esbuild/openbsd-arm64@0.27.3": + resolution: + { + integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openbsd] + + "@esbuild/openbsd-x64@0.27.3": + resolution: + { + integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [openbsd] + + "@esbuild/openharmony-arm64@0.27.3": + resolution: + { + integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [openharmony] + + "@esbuild/sunos-x64@0.27.3": + resolution: + { + integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [sunos] + + "@esbuild/win32-arm64@0.27.3": + resolution: + { + integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==, + } + engines: { node: ">=18" } + cpu: [arm64] + os: [win32] + + "@esbuild/win32-ia32@0.27.3": + resolution: + { + integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==, + } + engines: { node: ">=18" } + cpu: [ia32] + os: [win32] + + "@esbuild/win32-x64@0.27.3": + resolution: + { + integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==, + } + engines: { node: ">=18" } + cpu: [x64] + os: [win32] + "@eslint-community/eslint-utils@4.9.1": resolution: { @@ -367,6 +636,25 @@ packages: } deprecated: Use @eslint/object-schema instead + "@jridgewell/resolve-uri@3.1.2": + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: ">=6.0.0" } + + "@jridgewell/sourcemap-codec@1.5.5": + resolution: + { + integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==, + } + + "@jridgewell/trace-mapping@0.3.31": + resolution: + { + integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==, + } + "@lit-labs/ssr-dom-shim@1.5.1": resolution: { @@ -729,147 +1017,347 @@ packages: cpu: [riscv64] os: [linux] - "@oxc-resolver/binding-linux-riscv64-musl@11.16.4": + "@oxc-resolver/binding-linux-riscv64-musl@11.16.4": + resolution: + { + integrity: sha512-d09dOww9iKyEHSxuOQ/Iu2aYswl0j7ExBcyy14D6lJ5ijQSP9FXcJYJsJ3yvzboO/PDEFjvRuF41f8O1skiPVg==, + } + cpu: [riscv64] + os: [linux] + + "@oxc-resolver/binding-linux-s390x-gnu@11.16.4": + resolution: + { + integrity: sha512-lhjyGmUzTWHduZF3MkdUSEPMRIdExnhsqv8u1upX3A15epVn6YVwv4msFQPJl1x1wszkACPeDHGOtzHsITXGdw==, + } + cpu: [s390x] + os: [linux] + + "@oxc-resolver/binding-linux-x64-gnu@11.16.4": + resolution: + { + integrity: sha512-ZtqqiI5rzlrYBm/IMMDIg3zvvVj4WO/90Dg/zX+iA8lWaLN7K5nroXb17MQ4WhI5RqlEAgrnYDXW+hok1D9Kaw==, + } + cpu: [x64] + os: [linux] + + "@oxc-resolver/binding-linux-x64-musl@11.16.4": + resolution: + { + integrity: sha512-LM424h7aaKcMlqHnQWgTzO+GRNLyjcNnMpqm8SygEtFRVW693XS+XGXYvjORlmJtsyjo84ej1FMb3U2HE5eyjg==, + } + cpu: [x64] + os: [linux] + + "@oxc-resolver/binding-openharmony-arm64@11.16.4": + resolution: + { + integrity: sha512-8w8U6A5DDWTBv3OUxSD9fNk37liZuEC5jnAc9wQRv9DeYKAXvuUtBfT09aIZ58swaci0q1WS48/CoMVEO6jdCA==, + } + cpu: [arm64] + os: [openharmony] + + "@oxc-resolver/binding-wasm32-wasi@11.16.4": + resolution: + { + integrity: sha512-hnjb0mDVQOon6NdfNJ1EmNquonJUjoYkp7UyasjxVa4iiMcApziHP4czzzme6WZbp+vzakhVv2Yi5ACTon3Zlw==, + } + engines: { node: ">=14.0.0" } + cpu: [wasm32] + + "@oxc-resolver/binding-win32-arm64-msvc@11.16.4": + resolution: + { + integrity: sha512-+i0XtNfSP7cfnh1T8FMrMm4HxTeh0jxKP/VQCLWbjdUxaAQ4damho4gN9lF5dl0tZahtdszXLUboBFNloSJNOQ==, + } + cpu: [arm64] + os: [win32] + + "@oxc-resolver/binding-win32-ia32-msvc@11.16.4": + resolution: + { + integrity: sha512-ePW1islJrv3lPnef/iWwrjrSpRH8kLlftdKf2auQNWvYLx6F0xvcnv9d+r/upnVuttoQY9amLnWJf+JnCRksTw==, + } + cpu: [ia32] + os: [win32] + + "@oxc-resolver/binding-win32-x64-msvc@11.16.4": + resolution: + { + integrity: sha512-qnjQhjHI4TDL3hkidZyEmQRK43w2NHl6TP5Rnt/0XxYuLdEgx/1yzShhYidyqWzdnhGhSPTM/WVP2mK66XLegA==, + } + cpu: [x64] + os: [win32] + + "@paulmillr/qr@0.2.1": + resolution: + { + integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==, + } + deprecated: 'The package is now available as "qr": npm install qr' + + "@pkgr/core@0.2.9": + resolution: + { + integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==, + } + engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + + "@reown/appkit-common@1.7.8": + resolution: + { + integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==, + } + + "@reown/appkit-controllers@1.7.8": + resolution: + { + integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==, + } + + "@reown/appkit-pay@1.7.8": + resolution: + { + integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==, + } + + "@reown/appkit-polyfills@1.7.8": + resolution: + { + integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==, + } + + "@reown/appkit-scaffold-ui@1.7.8": + resolution: + { + integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==, + } + + "@reown/appkit-ui@1.7.8": + resolution: + { + integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==, + } + + "@reown/appkit-utils@1.7.8": + resolution: + { + integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==, + } + peerDependencies: + valtio: 1.13.2 + + "@reown/appkit-wallet@1.7.8": + resolution: + { + integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==, + } + + "@reown/appkit@1.7.8": + resolution: + { + integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==, + } + + "@rollup/rollup-android-arm-eabi@4.57.1": + resolution: + { + integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==, + } + cpu: [arm] + os: [android] + + "@rollup/rollup-android-arm64@4.57.1": + resolution: + { + integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==, + } + cpu: [arm64] + os: [android] + + "@rollup/rollup-darwin-arm64@4.57.1": + resolution: + { + integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==, + } + cpu: [arm64] + os: [darwin] + + "@rollup/rollup-darwin-x64@4.57.1": + resolution: + { + integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==, + } + cpu: [x64] + os: [darwin] + + "@rollup/rollup-freebsd-arm64@4.57.1": + resolution: + { + integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==, + } + cpu: [arm64] + os: [freebsd] + + "@rollup/rollup-freebsd-x64@4.57.1": resolution: { - integrity: sha512-d09dOww9iKyEHSxuOQ/Iu2aYswl0j7ExBcyy14D6lJ5ijQSP9FXcJYJsJ3yvzboO/PDEFjvRuF41f8O1skiPVg==, + integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==, } - cpu: [riscv64] - os: [linux] + cpu: [x64] + os: [freebsd] - "@oxc-resolver/binding-linux-s390x-gnu@11.16.4": + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": resolution: { - integrity: sha512-lhjyGmUzTWHduZF3MkdUSEPMRIdExnhsqv8u1upX3A15epVn6YVwv4msFQPJl1x1wszkACPeDHGOtzHsITXGdw==, + integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==, } - cpu: [s390x] + cpu: [arm] os: [linux] - "@oxc-resolver/binding-linux-x64-gnu@11.16.4": + "@rollup/rollup-linux-arm-musleabihf@4.57.1": resolution: { - integrity: sha512-ZtqqiI5rzlrYBm/IMMDIg3zvvVj4WO/90Dg/zX+iA8lWaLN7K5nroXb17MQ4WhI5RqlEAgrnYDXW+hok1D9Kaw==, + integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==, } - cpu: [x64] + cpu: [arm] os: [linux] - "@oxc-resolver/binding-linux-x64-musl@11.16.4": + "@rollup/rollup-linux-arm64-gnu@4.57.1": resolution: { - integrity: sha512-LM424h7aaKcMlqHnQWgTzO+GRNLyjcNnMpqm8SygEtFRVW693XS+XGXYvjORlmJtsyjo84ej1FMb3U2HE5eyjg==, + integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==, } - cpu: [x64] + cpu: [arm64] os: [linux] - "@oxc-resolver/binding-openharmony-arm64@11.16.4": + "@rollup/rollup-linux-arm64-musl@4.57.1": resolution: { - integrity: sha512-8w8U6A5DDWTBv3OUxSD9fNk37liZuEC5jnAc9wQRv9DeYKAXvuUtBfT09aIZ58swaci0q1WS48/CoMVEO6jdCA==, + integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==, } cpu: [arm64] - os: [openharmony] + os: [linux] - "@oxc-resolver/binding-wasm32-wasi@11.16.4": + "@rollup/rollup-linux-loong64-gnu@4.57.1": resolution: { - integrity: sha512-hnjb0mDVQOon6NdfNJ1EmNquonJUjoYkp7UyasjxVa4iiMcApziHP4czzzme6WZbp+vzakhVv2Yi5ACTon3Zlw==, + integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==, } - engines: { node: ">=14.0.0" } - cpu: [wasm32] + cpu: [loong64] + os: [linux] - "@oxc-resolver/binding-win32-arm64-msvc@11.16.4": + "@rollup/rollup-linux-loong64-musl@4.57.1": resolution: { - integrity: sha512-+i0XtNfSP7cfnh1T8FMrMm4HxTeh0jxKP/VQCLWbjdUxaAQ4damho4gN9lF5dl0tZahtdszXLUboBFNloSJNOQ==, + integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==, } - cpu: [arm64] - os: [win32] + cpu: [loong64] + os: [linux] - "@oxc-resolver/binding-win32-ia32-msvc@11.16.4": + "@rollup/rollup-linux-ppc64-gnu@4.57.1": resolution: { - integrity: sha512-ePW1islJrv3lPnef/iWwrjrSpRH8kLlftdKf2auQNWvYLx6F0xvcnv9d+r/upnVuttoQY9amLnWJf+JnCRksTw==, + integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==, } - cpu: [ia32] - os: [win32] + cpu: [ppc64] + os: [linux] - "@oxc-resolver/binding-win32-x64-msvc@11.16.4": + "@rollup/rollup-linux-ppc64-musl@4.57.1": resolution: { - integrity: sha512-qnjQhjHI4TDL3hkidZyEmQRK43w2NHl6TP5Rnt/0XxYuLdEgx/1yzShhYidyqWzdnhGhSPTM/WVP2mK66XLegA==, + integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==, } - cpu: [x64] - os: [win32] + cpu: [ppc64] + os: [linux] - "@paulmillr/qr@0.2.1": + "@rollup/rollup-linux-riscv64-gnu@4.57.1": resolution: { - integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==, + integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==, } - deprecated: 'The package is now available as "qr": npm install qr' + cpu: [riscv64] + os: [linux] - "@pkgr/core@0.2.9": + "@rollup/rollup-linux-riscv64-musl@4.57.1": resolution: { - integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==, + integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==, } - engines: { node: ^12.20.0 || ^14.18.0 || >=16.0.0 } + cpu: [riscv64] + os: [linux] - "@reown/appkit-common@1.7.8": + "@rollup/rollup-linux-s390x-gnu@4.57.1": resolution: { - integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==, + integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==, } + cpu: [s390x] + os: [linux] - "@reown/appkit-controllers@1.7.8": + "@rollup/rollup-linux-x64-gnu@4.57.1": resolution: { - integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==, + integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==, } + cpu: [x64] + os: [linux] - "@reown/appkit-pay@1.7.8": + "@rollup/rollup-linux-x64-musl@4.57.1": resolution: { - integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==, + integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==, } + cpu: [x64] + os: [linux] - "@reown/appkit-polyfills@1.7.8": + "@rollup/rollup-openbsd-x64@4.57.1": resolution: { - integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==, + integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==, } + cpu: [x64] + os: [openbsd] - "@reown/appkit-scaffold-ui@1.7.8": + "@rollup/rollup-openharmony-arm64@4.57.1": resolution: { - integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==, + integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==, } + cpu: [arm64] + os: [openharmony] - "@reown/appkit-ui@1.7.8": + "@rollup/rollup-win32-arm64-msvc@4.57.1": resolution: { - integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==, + integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==, } + cpu: [arm64] + os: [win32] - "@reown/appkit-utils@1.7.8": + "@rollup/rollup-win32-ia32-msvc@4.57.1": resolution: { - integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==, + integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==, } - peerDependencies: - valtio: 1.13.2 + cpu: [ia32] + os: [win32] - "@reown/appkit-wallet@1.7.8": + "@rollup/rollup-win32-x64-gnu@4.57.1": resolution: { - integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==, + integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==, } + cpu: [x64] + os: [win32] - "@reown/appkit@1.7.8": + "@rollup/rollup-win32-x64-msvc@4.57.1": resolution: { - integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==, + integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==, } + cpu: [x64] + os: [win32] "@rtsao/scc@1.1.0": resolution: @@ -1485,6 +1973,12 @@ packages: integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==, } + "@standard-schema/spec@1.1.0": + resolution: + { + integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==, + } + "@swc/helpers@0.5.18": resolution: { @@ -1517,6 +2011,12 @@ packages: integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==, } + "@types/chai@5.2.3": + resolution: + { + integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==, + } + "@types/connect@3.4.38": resolution: { @@ -1535,6 +2035,18 @@ packages: integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==, } + "@types/deep-eql@4.0.2": + resolution: + { + integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==, + } + + "@types/estree@1.0.8": + resolution: + { + integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==, + } + "@types/json5@0.0.29": resolution: { @@ -1888,6 +2400,18 @@ packages: cpu: [x64] os: [win32] + "@vitest/coverage-v8@4.0.18": + resolution: + { + integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==, + } + peerDependencies: + "@vitest/browser": 4.0.18 + vitest: 4.0.18 + peerDependenciesMeta: + "@vitest/browser": + optional: true + "@vitest/eslint-plugin@1.6.6": resolution: { @@ -1904,6 +2428,56 @@ packages: vitest: optional: true + "@vitest/expect@4.0.18": + resolution: + { + integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==, + } + + "@vitest/mocker@4.0.18": + resolution: + { + integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==, + } + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + "@vitest/pretty-format@4.0.18": + resolution: + { + integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==, + } + + "@vitest/runner@4.0.18": + resolution: + { + integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==, + } + + "@vitest/snapshot@4.0.18": + resolution: + { + integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==, + } + + "@vitest/spy@4.0.18": + resolution: + { + integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==, + } + + "@vitest/utils@4.0.18": + resolution: + { + integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==, + } + "@wagmi/connectors@6.2.0": resolution: { @@ -2321,12 +2895,25 @@ packages: } engines: { node: ">= 0.4" } + assertion-error@2.0.1: + resolution: + { + integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, + } + engines: { node: ">=12" } + ast-types-flow@0.0.8: resolution: { integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==, } + ast-v8-to-istanbul@0.3.11: + resolution: + { + integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==, + } + async-function@1.0.0: resolution: { @@ -2531,6 +3118,13 @@ packages: } engines: { node: ">=6" } + chai@6.2.2: + resolution: + { + integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==, + } + engines: { node: ">=18" } + chalk@4.1.2: resolution: { @@ -3097,6 +3691,12 @@ packages: } engines: { node: ">= 0.4" } + es-module-lexer@1.7.0: + resolution: + { + integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==, + } + es-object-atoms@1.1.1: resolution: { @@ -3143,6 +3743,14 @@ packages: integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==, } + esbuild@0.27.3: + resolution: + { + integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==, + } + engines: { node: ">=18" } + hasBin: true + escalade@3.2.0: resolution: { @@ -3486,6 +4094,12 @@ packages: } engines: { node: ">=4.0" } + estree-walker@3.0.3: + resolution: + { + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, + } + esutils@2.0.3: resolution: { @@ -3550,6 +4164,13 @@ packages: } engines: { node: ">=0.8.x" } + expect-type@1.3.0: + resolution: + { + integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==, + } + engines: { node: ">=12.0.0" } + extension-port-stream@3.0.0: resolution: { @@ -3733,6 +4354,14 @@ packages: integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, } + fsevents@2.3.3: + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } + os: [darwin] + function-bind@1.1.2: resolution: { @@ -3944,6 +4573,12 @@ packages: } engines: { node: ">=16.9.0" } + html-escaper@2.0.2: + resolution: + { + integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==, + } + humanize-ms@1.2.1: resolution: { @@ -4341,6 +4976,27 @@ packages: peerDependencies: ws: "*" + istanbul-lib-coverage@3.2.2: + resolution: + { + integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==, + } + engines: { node: ">=8" } + + istanbul-lib-report@3.0.1: + resolution: + { + integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==, + } + engines: { node: ">=10" } + + istanbul-reports@3.2.0: + resolution: + { + integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==, + } + engines: { node: ">=8" } + iterator.prototype@1.1.5: resolution: { @@ -4369,6 +5025,12 @@ packages: integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==, } + js-tokens@10.0.0: + resolution: + { + integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==, + } + js-tokens@4.0.0: resolution: { @@ -4676,6 +5338,25 @@ packages: } engines: { node: 20 || >=22 } + magic-string@0.30.21: + resolution: + { + integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==, + } + + magicast@0.5.2: + resolution: + { + integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==, + } + + make-dir@4.0.0: + resolution: + { + integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==, + } + engines: { node: ">=10" } + markdown-it@14.1.0: resolution: { @@ -4826,6 +5507,14 @@ packages: } engines: { node: ">=20.17" } + nanoid@3.3.11: + resolution: + { + integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } + hasBin: true + napi-postinstall@0.3.4: resolution: { @@ -4952,6 +5641,12 @@ packages: } engines: { node: ">= 0.4" } + obug@2.1.1: + resolution: + { + integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==, + } + ofetch@1.5.1: resolution: { @@ -5165,6 +5860,12 @@ packages: } engines: { node: ">=8" } + pathe@2.0.3: + resolution: + { + integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==, + } + picocolors@1.1.1: resolution: { @@ -5282,6 +5983,13 @@ packages: } engines: { node: ">= 0.4" } + postcss@8.5.6: + resolution: + { + integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, + } + engines: { node: ^10 || ^12 || >=14 } + preact@10.24.2: resolution: { @@ -5542,6 +6250,14 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rollup@4.57.1: + resolution: + { + integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==, + } + engines: { node: ">=18.0.0", npm: ">=8.0.0" } + hasBin: true + rpc-websockets@9.3.3: resolution: { @@ -5686,6 +6402,12 @@ packages: } engines: { node: ">= 0.4" } + siginfo@2.0.0: + resolution: + { + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, + } + signal-exit@4.1.0: resolution: { @@ -5749,10 +6471,17 @@ packages: sort-package-json@3.6.1: resolution: { - integrity: sha512-Chgejw1+10p2D0U2tB7au1lHtz6TkFnxmvZktyBCRyV0GgmF6nl1IxXxAsPtJVsUyg/fo+BfCMAVVFUVRkAHrQ==, + integrity: sha512-Chgejw1+10p2D0U2tB7au1lHtz6TkFnxmvZktyBCRyV0GgmF6nl1IxXxAsPtJVsUyg/fo+BfCMAVVFUVRkAHrQ==, + } + engines: { node: ">=20" } + hasBin: true + + source-map-js@1.2.1: + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, } - engines: { node: ">=20" } - hasBin: true + engines: { node: ">=0.10.0" } spdx-exceptions@2.5.0: resolution: @@ -5792,6 +6521,18 @@ packages: integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==, } + stackback@0.0.2: + resolution: + { + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, + } + + std-env@3.10.0: + resolution: + { + integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==, + } + stop-iteration-iterator@1.1.0: resolution: { @@ -6006,6 +6747,12 @@ packages: integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, } + tinybench@2.9.0: + resolution: + { + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, + } + tinyexec@1.0.2: resolution: { @@ -6020,6 +6767,13 @@ packages: } engines: { node: ">=12.0.0" } + tinyrainbow@3.0.3: + resolution: + { + integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==, + } + engines: { node: ">=14.0.0" } + to-buffer@1.2.2: resolution: { @@ -6355,6 +7109,86 @@ packages: typescript: optional: true + vite@7.3.1: + resolution: + { + integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==, + } + engines: { node: ^20.19.0 || >=22.12.0 } + hasBin: true + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + jiti: ">=1.21.0" + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + "@types/node": + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.18: + resolution: + { + integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==, + } + engines: { node: ^20.0.0 || ^22.0.0 || >=24.0.0 } + hasBin: true + peerDependencies: + "@edge-runtime/vm": "*" + "@opentelemetry/api": ^1.9.0 + "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 + "@vitest/browser-playwright": 4.0.18 + "@vitest/browser-preview": 4.0.18 + "@vitest/browser-webdriverio": 4.0.18 + "@vitest/ui": 4.0.18 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@opentelemetry/api": + optional: true + "@types/node": + optional: true + "@vitest/browser-playwright": + optional: true + "@vitest/browser-preview": + optional: true + "@vitest/browser-webdriverio": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + wagmi@2.19.5: resolution: { @@ -6436,6 +7270,14 @@ packages: engines: { node: ">= 8" } hasBin: true + why-is-node-running@2.3.0: + resolution: + { + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, + } + engines: { node: ">=8" } + hasBin: true + word-wrap@1.2.5: resolution: { @@ -6699,10 +7541,21 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + "@babel/helper-string-parser@7.27.1": {} + "@babel/helper-validator-identifier@7.28.5": {} + "@babel/parser@7.29.0": + dependencies: + "@babel/types": 7.29.0 + "@babel/runtime@7.28.6": {} + "@babel/types@7.29.0": + dependencies: + "@babel/helper-string-parser": 7.27.1 + "@babel/helper-validator-identifier": 7.28.5 + "@base-org/account@2.4.0(@types/react@19.2.10)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@4.3.6)": dependencies: "@coinbase/cdp-sdk": 1.43.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10) @@ -6727,6 +7580,8 @@ snapshots: - utf-8-validate - zod + "@bcoe/v8-coverage@1.0.2": {} + "@coinbase/cdp-sdk@1.43.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)": dependencies: "@solana-program/system": 0.10.0(@solana/kit@5.5.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)) @@ -6914,6 +7769,84 @@ snapshots: esquery: 1.7.0 jsdoc-type-pratt-parser: 4.0.0 + "@esbuild/aix-ppc64@0.27.3": + optional: true + + "@esbuild/android-arm64@0.27.3": + optional: true + + "@esbuild/android-arm@0.27.3": + optional: true + + "@esbuild/android-x64@0.27.3": + optional: true + + "@esbuild/darwin-arm64@0.27.3": + optional: true + + "@esbuild/darwin-x64@0.27.3": + optional: true + + "@esbuild/freebsd-arm64@0.27.3": + optional: true + + "@esbuild/freebsd-x64@0.27.3": + optional: true + + "@esbuild/linux-arm64@0.27.3": + optional: true + + "@esbuild/linux-arm@0.27.3": + optional: true + + "@esbuild/linux-ia32@0.27.3": + optional: true + + "@esbuild/linux-loong64@0.27.3": + optional: true + + "@esbuild/linux-mips64el@0.27.3": + optional: true + + "@esbuild/linux-ppc64@0.27.3": + optional: true + + "@esbuild/linux-riscv64@0.27.3": + optional: true + + "@esbuild/linux-s390x@0.27.3": + optional: true + + "@esbuild/linux-x64@0.27.3": + optional: true + + "@esbuild/netbsd-arm64@0.27.3": + optional: true + + "@esbuild/netbsd-x64@0.27.3": + optional: true + + "@esbuild/openbsd-arm64@0.27.3": + optional: true + + "@esbuild/openbsd-x64@0.27.3": + optional: true + + "@esbuild/openharmony-arm64@0.27.3": + optional: true + + "@esbuild/sunos-x64@0.27.3": + optional: true + + "@esbuild/win32-arm64@0.27.3": + optional: true + + "@esbuild/win32-ia32@0.27.3": + optional: true + + "@esbuild/win32-x64@0.27.3": + optional: true + "@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)": dependencies: eslint: 8.57.1 @@ -6979,6 +7912,15 @@ snapshots: "@humanwhocodes/object-schema@2.0.3": {} + "@jridgewell/resolve-uri@3.1.2": {} + + "@jridgewell/sourcemap-codec@1.5.5": {} + + "@jridgewell/trace-mapping@0.3.31": + dependencies: + "@jridgewell/resolve-uri": 3.1.2 + "@jridgewell/sourcemap-codec": 1.5.5 + "@lit-labs/ssr-dom-shim@1.5.1": {} "@lit/reactive-element@2.1.2": @@ -7561,6 +8503,81 @@ snapshots: - utf-8-validate - zod + "@rollup/rollup-android-arm-eabi@4.57.1": + optional: true + + "@rollup/rollup-android-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-arm64@4.57.1": + optional: true + + "@rollup/rollup-darwin-x64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-arm64@4.57.1": + optional: true + + "@rollup/rollup-freebsd-x64@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-gnueabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm-musleabihf@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-arm64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-loong64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-ppc64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-riscv64-musl@4.57.1": + optional: true + + "@rollup/rollup-linux-s390x-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-linux-x64-musl@4.57.1": + optional: true + + "@rollup/rollup-openbsd-x64@4.57.1": + optional: true + + "@rollup/rollup-openharmony-arm64@4.57.1": + optional: true + + "@rollup/rollup-win32-arm64-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-ia32-msvc@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-gnu@4.57.1": + optional: true + + "@rollup/rollup-win32-x64-msvc@4.57.1": + optional: true + "@rtsao/scc@1.1.0": {} "@rushstack/eslint-patch@1.15.0": {} @@ -8102,6 +9119,8 @@ snapshots: - typescript - utf-8-validate + "@standard-schema/spec@1.1.0": {} + "@swc/helpers@0.5.18": dependencies: tslib: 2.8.1 @@ -8120,6 +9139,11 @@ snapshots: tslib: 2.8.1 optional: true + "@types/chai@5.2.3": + dependencies: + "@types/deep-eql": 4.0.2 + assertion-error: 2.0.1 + "@types/connect@3.4.38": dependencies: "@types/node": 25.0.10 @@ -8132,6 +9156,10 @@ snapshots: dependencies: "@types/ms": 2.1.0 + "@types/deep-eql@4.0.2": {} + + "@types/estree@1.0.8": {} + "@types/json5@0.0.29": {} "@types/lodash@4.17.23": {} @@ -8352,16 +9380,70 @@ snapshots: "@unrs/resolver-binding-win32-x64-msvc@1.11.1": optional: true - "@vitest/eslint-plugin@1.6.6(eslint@8.57.1)(typescript@5.9.3)": + "@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2))": + dependencies: + "@bcoe/v8-coverage": 1.0.2 + "@vitest/utils": 4.0.18 + ast-v8-to-istanbul: 0.3.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 3.10.0 + tinyrainbow: 3.0.3 + vitest: 4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2) + + "@vitest/eslint-plugin@1.6.6(eslint@8.57.1)(typescript@5.9.3)(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2))": dependencies: "@typescript-eslint/scope-manager": 8.54.0 "@typescript-eslint/utils": 8.54.0(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 optionalDependencies: typescript: 5.9.3 + vitest: 4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2) transitivePeerDependencies: - supports-color + "@vitest/expect@4.0.18": + dependencies: + "@standard-schema/spec": 1.1.0 + "@types/chai": 5.2.3 + "@vitest/spy": 4.0.18 + "@vitest/utils": 4.0.18 + chai: 6.2.2 + tinyrainbow: 3.0.3 + + "@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2))": + dependencies: + "@vitest/spy": 4.0.18 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2) + + "@vitest/pretty-format@4.0.18": + dependencies: + tinyrainbow: 3.0.3 + + "@vitest/runner@4.0.18": + dependencies: + "@vitest/utils": 4.0.18 + pathe: 2.0.3 + + "@vitest/snapshot@4.0.18": + dependencies: + "@vitest/pretty-format": 4.0.18 + magic-string: 0.30.21 + pathe: 2.0.3 + + "@vitest/spy@4.0.18": {} + + "@vitest/utils@4.0.18": + dependencies: + "@vitest/pretty-format": 4.0.18 + tinyrainbow: 3.0.3 + "@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.20(react@19.2.4))(@types/react@19.2.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.20)(@types/react@19.2.10)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)))(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@types/react@19.2.10)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@4.3.6))(zod@4.3.6)": dependencies: "@base-org/account": 2.4.0(@types/react@19.2.10)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@4.3.6) @@ -9117,8 +10199,16 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + ast-types-flow@0.0.8: {} + ast-v8-to-istanbul@0.3.11: + dependencies: + "@jridgewell/trace-mapping": 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + async-function@1.0.0: {} async-mutex@0.2.6: @@ -9231,6 +10321,8 @@ snapshots: camelcase@5.3.1: {} + chai@6.2.2: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -9591,6 +10683,8 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -9620,6 +10714,35 @@ snapshots: dependencies: es6-promise: 4.2.8 + esbuild@0.27.3: + optionalDependencies: + "@esbuild/aix-ppc64": 0.27.3 + "@esbuild/android-arm": 0.27.3 + "@esbuild/android-arm64": 0.27.3 + "@esbuild/android-x64": 0.27.3 + "@esbuild/darwin-arm64": 0.27.3 + "@esbuild/darwin-x64": 0.27.3 + "@esbuild/freebsd-arm64": 0.27.3 + "@esbuild/freebsd-x64": 0.27.3 + "@esbuild/linux-arm": 0.27.3 + "@esbuild/linux-arm64": 0.27.3 + "@esbuild/linux-ia32": 0.27.3 + "@esbuild/linux-loong64": 0.27.3 + "@esbuild/linux-mips64el": 0.27.3 + "@esbuild/linux-ppc64": 0.27.3 + "@esbuild/linux-riscv64": 0.27.3 + "@esbuild/linux-s390x": 0.27.3 + "@esbuild/linux-x64": 0.27.3 + "@esbuild/netbsd-arm64": 0.27.3 + "@esbuild/netbsd-x64": 0.27.3 + "@esbuild/openbsd-arm64": 0.27.3 + "@esbuild/openbsd-x64": 0.27.3 + "@esbuild/openharmony-arm64": 0.27.3 + "@esbuild/sunos-x64": 0.27.3 + "@esbuild/win32-arm64": 0.27.3 + "@esbuild/win32-ia32": 0.27.3 + "@esbuild/win32-x64": 0.27.3 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -9629,11 +10752,11 @@ snapshots: eslint: 8.57.1 semver: 7.7.3 - eslint-config-bloq@4.7.0(eslint@8.57.1)(typescript@5.9.3): + eslint-config-bloq@4.7.0(@types/estree@1.0.8)(eslint@8.57.1)(typescript@5.9.3)(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2)): dependencies: "@typescript-eslint/eslint-plugin": 8.54.0(@typescript-eslint/parser@8.54.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) "@typescript-eslint/parser": 8.54.0(eslint@8.57.1)(typescript@5.9.3) - "@vitest/eslint-plugin": 1.6.6(eslint@8.57.1)(typescript@5.9.3) + "@vitest/eslint-plugin": 1.6.6(eslint@8.57.1)(typescript@5.9.3)(vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2)) eslint: 8.57.1 eslint-config-next: 13.5.11(eslint@8.57.1)(typescript@5.9.3) eslint-config-prettier: 8.10.2(eslint@8.57.1) @@ -9643,7 +10766,7 @@ snapshots: eslint-plugin-markdownlint: 0.6.0(eslint@8.57.1) eslint-plugin-mocha: 10.5.0(eslint@8.57.1) eslint-plugin-node: 11.1.0(eslint@8.57.1) - eslint-plugin-package-json: 0.31.0(eslint@8.57.1)(jsonc-eslint-parser@2.4.2) + eslint-plugin-package-json: 0.31.0(@types/estree@1.0.8)(eslint@8.57.1)(jsonc-eslint-parser@2.4.2) eslint-plugin-prefer-arrow: 1.2.3(eslint@8.57.1) eslint-plugin-promise: 6.6.0(eslint@8.57.1) eslint-plugin-sort-destructure-keys: 2.0.0(eslint@8.57.1) @@ -9681,9 +10804,11 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-fix-utils@0.2.1(eslint@8.57.1): + eslint-fix-utils@0.2.1(@types/estree@1.0.8)(eslint@8.57.1): dependencies: eslint: 8.57.1 + optionalDependencies: + "@types/estree": 1.0.8 eslint-import-resolver-node@0.3.9: dependencies: @@ -9830,13 +10955,13 @@ snapshots: resolve: 1.22.11 semver: 6.3.1 - eslint-plugin-package-json@0.31.0(eslint@8.57.1)(jsonc-eslint-parser@2.4.2): + eslint-plugin-package-json@0.31.0(@types/estree@1.0.8)(eslint@8.57.1)(jsonc-eslint-parser@2.4.2): dependencies: "@altano/repository-tools": 0.1.1 detect-indent: 6.1.0 detect-newline: 3.1.0 eslint: 8.57.1 - eslint-fix-utils: 0.2.1(eslint@8.57.1) + eslint-fix-utils: 0.2.1(@types/estree@1.0.8)(eslint@8.57.1) jsonc-eslint-parser: 2.4.2 package-json-validator: 0.10.2 semver: 7.7.3 @@ -9966,6 +11091,10 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + "@types/estree": 1.0.8 + esutils@2.0.3: {} eth-block-tracker@7.1.0: @@ -10010,6 +11139,8 @@ snapshots: events@3.3.0: {} + expect-type@1.3.0: {} + extension-port-stream@3.0.0: dependencies: readable-stream: 3.6.2 @@ -10105,6 +11236,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -10248,6 +11382,8 @@ snapshots: hono@4.11.7: {} + html-escaper@2.0.2: {} + humanize-ms@1.2.1: dependencies: ms: 2.1.3 @@ -10449,6 +11585,19 @@ snapshots: dependencies: ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -10480,6 +11629,8 @@ snapshots: jose@6.1.3: {} + js-tokens@10.0.0: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -10664,6 +11815,20 @@ snapshots: lru-cache@11.2.5: {} + magic-string@0.30.21: + dependencies: + "@jridgewell/sourcemap-codec": 1.5.5 + + magicast@0.5.2: + dependencies: + "@babel/parser": 7.29.0 + "@babel/types": 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.3 + markdown-it@14.1.0: dependencies: argparse: 2.0.1 @@ -10735,6 +11900,8 @@ snapshots: nano-spawn@2.0.0: {} + nanoid@3.3.11: {} + napi-postinstall@0.3.4: {} natural-compare-lite@1.4.0: {} @@ -10803,6 +11970,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obug@2.1.1: {} + ofetch@1.5.1: dependencies: destr: 2.0.5 @@ -11004,6 +12173,8 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -11063,6 +12234,12 @@ snapshots: possible-typed-array-names@1.1.0: {} + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + preact@10.24.2: {} preact@10.28.2: {} @@ -11199,6 +12376,37 @@ snapshots: dependencies: glob: 7.2.3 + rollup@4.57.1: + dependencies: + "@types/estree": 1.0.8 + optionalDependencies: + "@rollup/rollup-android-arm-eabi": 4.57.1 + "@rollup/rollup-android-arm64": 4.57.1 + "@rollup/rollup-darwin-arm64": 4.57.1 + "@rollup/rollup-darwin-x64": 4.57.1 + "@rollup/rollup-freebsd-arm64": 4.57.1 + "@rollup/rollup-freebsd-x64": 4.57.1 + "@rollup/rollup-linux-arm-gnueabihf": 4.57.1 + "@rollup/rollup-linux-arm-musleabihf": 4.57.1 + "@rollup/rollup-linux-arm64-gnu": 4.57.1 + "@rollup/rollup-linux-arm64-musl": 4.57.1 + "@rollup/rollup-linux-loong64-gnu": 4.57.1 + "@rollup/rollup-linux-loong64-musl": 4.57.1 + "@rollup/rollup-linux-ppc64-gnu": 4.57.1 + "@rollup/rollup-linux-ppc64-musl": 4.57.1 + "@rollup/rollup-linux-riscv64-gnu": 4.57.1 + "@rollup/rollup-linux-riscv64-musl": 4.57.1 + "@rollup/rollup-linux-s390x-gnu": 4.57.1 + "@rollup/rollup-linux-x64-gnu": 4.57.1 + "@rollup/rollup-linux-x64-musl": 4.57.1 + "@rollup/rollup-openbsd-x64": 4.57.1 + "@rollup/rollup-openharmony-arm64": 4.57.1 + "@rollup/rollup-win32-arm64-msvc": 4.57.1 + "@rollup/rollup-win32-ia32-msvc": 4.57.1 + "@rollup/rollup-win32-x64-gnu": 4.57.1 + "@rollup/rollup-win32-x64-msvc": 4.57.1 + fsevents: 2.3.3 + rpc-websockets@9.3.3: dependencies: "@swc/helpers": 0.5.18 @@ -11309,6 +12517,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@4.1.0: {} slash@3.0.0: {} @@ -11356,6 +12566,8 @@ snapshots: sort-object-keys: 2.1.0 tinyglobby: 0.2.15 + source-map-js@1.2.1: {} + spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: @@ -11371,6 +12583,10 @@ snapshots: stable-hash@0.0.5: {} + stackback@0.0.2: {} + + std-env@3.10.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -11503,6 +12719,8 @@ snapshots: through@2.3.8: {} + tinybench@2.9.0: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -11510,6 +12728,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinyrainbow@3.0.3: {} + to-buffer@1.2.2: dependencies: isarray: 2.0.5 @@ -11755,6 +12975,57 @@ snapshots: - utf-8-validate - zod + vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.57.1 + tinyglobby: 0.2.15 + optionalDependencies: + "@types/node": 25.0.10 + fsevents: 2.3.3 + jiti: 2.6.1 + yaml: 2.8.2 + + vitest@4.0.18(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2): + dependencies: + "@vitest/expect": 4.0.18 + "@vitest/mocker": 4.0.18(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2)) + "@vitest/pretty-format": 4.0.18 + "@vitest/runner": 4.0.18 + "@vitest/snapshot": 4.0.18 + "@vitest/spy": 4.0.18 + "@vitest/utils": 4.0.18 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + "@types/node": 25.0.10 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + wagmi@2.19.5(@tanstack/query-core@5.90.20)(@tanstack/react-query@5.90.20(react@19.2.4))(@types/react@19.2.10)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.45.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@4.3.6): dependencies: "@tanstack/react-query": 5.90.20(react@19.2.4) @@ -11858,6 +13129,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} wrap-ansi@6.2.0: diff --git a/src/useEstimateApproveErc20Fees.ts b/src/useEstimateApproveErc20Fees.ts new file mode 100644 index 0000000..6afccf8 --- /dev/null +++ b/src/useEstimateApproveErc20Fees.ts @@ -0,0 +1,33 @@ +import { type Address, type Chain, encodeFunctionData, erc20Abi } from "viem"; +import { useEstimateGas } from "wagmi"; + +import { useEstimateFees } from "./useEstimateFees"; + +export const useEstimateApproveErc20Fees = function ({ + amount, + enabled = true, + spender, + token, +}: { + amount: bigint; + enabled?: boolean; + spender: Address; + token: { address: Address; chainId: Chain["id"] }; +}) { + const { data: gasUnits, isError } = useEstimateGas({ + chainId: token.chainId, + data: encodeFunctionData({ + abi: erc20Abi, + args: [spender, amount], + functionName: "approve", + }), + query: { enabled: enabled && amount > BigInt(0) }, + to: token.address, + }); + + return useEstimateFees({ + chainId: token.chainId, + gasUnits, + isGasUnitsError: isError, + }); +}; diff --git a/src/useEstimateFees.ts b/src/useEstimateFees.ts new file mode 100644 index 0000000..9b606e9 --- /dev/null +++ b/src/useEstimateFees.ts @@ -0,0 +1,75 @@ +import { parseEther } from "viem/utils"; +import { useEstimateMaxPriorityFeePerGas, useFeeHistory } from "wagmi"; + +import { estimateTotalFee } from "./utils/fees"; + +const defaultBlockCount = 4; +const defaultOverEstimation = 1.5; +const defaultFallbackPriorityFee = parseEther("1", "gwei"); + +type UseEstimateFees = { + chainId: number; + isGasUnitsError?: boolean; + overEstimation?: number; + gasUnits?: bigint; + fallbackPriorityFee?: bigint; +}; + +/** + * Custom hook to estimate the total transaction fee for an EIP-1559 compatible network. + * + * It uses recent base fee history and a suggested or fallback maxPriorityFeePerGas to + * calculate a conservative `maxFeePerGas`, and multiplies it by the estimated gas units. + * This hook supports a custom `overEstimation` factor to pad the result for safety. + * + * @param {Object} params - Hook parameters. + * @param {number} params.chainId - The chain ID of the target network. + * @param {bigint | undefined} params.gasUnits - Estimated gas units for the transaction. + * @param {boolean} [params.isGasUnitsError=false] - Whether there was an error in estimating gas units. + * @param {number} [params.overEstimation=1.5] - Optional multiplier to pad the estimated fee for safety. + * @param {bigint} [params.fallbackPriorityFee=1000000000n] - Fallback priority fee in wei to use when maxPriorityFeePerGas is unavailable or too low. + * + * @returns {Object} Result object. + * @returns {bigint | undefined} result.fees - Estimated total fee in wei. + * @returns {boolean} result.isError - Indicates whether there was a gas estimation error. + */ +export function useEstimateFees({ + chainId, + fallbackPriorityFee = defaultFallbackPriorityFee, + gasUnits, + isGasUnitsError = false, + overEstimation = defaultOverEstimation, +}: UseEstimateFees) { + const { data: feeHistory, isError: isFeeHistoryError } = useFeeHistory({ + blockCount: defaultBlockCount, + blockTag: "latest", + chainId, + query: { + enabled: gasUnits !== undefined, + // re-estimate every 5 blocks approximately + refetchInterval: 60 * 1000, + }, + rewardPercentiles: [30], + }); + + const { data: maxPriorityFeePerGas, isError: isMaxPriorityFeePerGasError } = + useEstimateMaxPriorityFeePerGas({ chainId }); + + // Use the base fee from the latest block in the fee history. + // This value is in wei and reflects the current network congestion. + const baseFeePerGas = feeHistory?.baseFeePerGas?.at(-1); + + const fees = estimateTotalFee({ + baseFeePerGas, + fallbackPriorityFee, + gasUnits, + maxPriorityFeePerGas, + overEstimation, + }); + + return { + fees, + isError: + isGasUnitsError || isFeeHistoryError || isMaxPriorityFeePerGasError, + }; +} diff --git a/src/utils/fees.test.ts b/src/utils/fees.test.ts new file mode 100644 index 0000000..5a44c37 --- /dev/null +++ b/src/utils/fees.test.ts @@ -0,0 +1,250 @@ +import { parseEther } from "viem/utils"; +import { describe, expect, it } from "vitest"; + +import { estimateTotalFee } from "./fees"; + +// Base valid parameters for all tests +const validParameters = { + baseFeePerGas: parseEther("10", "gwei"), + fallbackPriorityFee: parseEther("1", "gwei"), + gasUnits: 21000n, + // note it's above fallbackPriorityFee + maxPriorityFeePerGas: parseEther("2", "gwei"), + overEstimation: 1.0, +}; + +describe("estimateTotalFee", function () { + it("should use fallbackPriorityFee when priority fee is zero", function () { + const result = estimateTotalFee({ + ...validParameters, + maxPriorityFeePerGas: 0n, + }); + // maxFeePerGas = (10 * 2) + 1 = 21 Gwei + // total = 21000 * 21 Gwei = 441000 Gwei + expect(result).toBe(parseEther("441000", "gwei")); + }); + + it("should use fallbackPriorityFee when priority fee is below fallbackPriorityFee", function () { + const result = estimateTotalFee({ + ...validParameters, + maxPriorityFeePerGas: validParameters.fallbackPriorityFee - 1n, + }); + // maxFeePerGas = (10 * 2) + 1 = 21 Gwei (fallback used) + // total = 21000 * 21 Gwei = 441000 Gwei + expect(result).toBe(parseEther("441000", "gwei")); + }); + + it("should use actual priority fee when priority fee is above fallbackPriorityFee", function () { + const result = estimateTotalFee(validParameters); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 21000 * 22 Gwei = 462000 Gwei + expect(result).toBe(parseEther("462000", "gwei")); + }); + + it("should use fallbackPriorityFee when priority fee is undefined on default chain", function () { + const result = estimateTotalFee({ + ...validParameters, + maxPriorityFeePerGas: undefined, + }); + // maxFeePerGas = (10 * 2) + 1 = 21 Gwei (fallback used) + // total = 21000 * 21 Gwei = 441000 Gwei + expect(result).toBe(parseEther("441000", "gwei")); + }); + + it("should handle zero base fee correctly", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: 0n, + }); + // maxFeePerGas = (0 * 2) + 2 = 2 Gwei + expect(result).toBe(parseEther("42000", "gwei")); + }); + + it("should handle very large base fee correctly", function () { + const largeBaseFee = 1000n * parseEther("1", "gwei"); // 1000 Gwei + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: largeBaseFee, + }); + // maxFeePerGas = (1000 * 2) + 2 = 2002 Gwei + expect(result).toBe(parseEther("42042000", "gwei")); + }); + + it("should apply default over-estimation of 1.5x", function () { + const result = estimateTotalFee({ + ...validParameters, + // overEstimation defaults to 1.5 + overEstimation: undefined, + }); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 21000 * 22 Gwei * 1.5 = 693000 Gwei + expect(result).toBe(parseEther("693000", "gwei")); + }); + + it("should apply no over-estimation when set to 1.0", function () { + const result = estimateTotalFee(validParameters); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 21000 * 22 Gwei * 1.0 = 462000 Gwei + expect(result).toBe(parseEther("462000", "gwei")); + }); + + it("should apply 2.0x over-estimation", function () { + const result = estimateTotalFee({ + ...validParameters, + overEstimation: 2.0, + }); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 21000 * 22 Gwei * 2.0 = 924000 Gwei + expect(result).toBe(parseEther("924000", "gwei")); + }); + + it("should apply fractional over-estimation 1.25x correctly", function () { + const result = estimateTotalFee({ + ...validParameters, + overEstimation: 1.25, + }); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 21000 * 22 Gwei * 1.25 + // = 462000 Gwei * 1.25 = 577500 Gwei + expect(result).toBe(parseEther("577500", "gwei")); + }); + + it("should handle fractional over-estimation with proper rounding", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: parseEther("1", "gwei"), + gasUnits: 1000n, + maxPriorityFeePerGas: parseEther("1", "gwei"), + overEstimation: 1.333, // Should round to 1333 + }); + // maxFeePerGas = (1 Gwei * 2) + 1 Gwei = 3 Gwei + // total = 1000 * 3 Gwei * 1333 / 1000 = 3999 Gwei + expect(result).toBe(parseEther("3999", "gwei")); + }); + + it("should return zero when gas units is zero", function () { + const result = estimateTotalFee({ + ...validParameters, + gasUnits: 0n, + }); + expect(result).toBe(0n); + }); + + it("should return undefined when gas units is undefined", function () { + const result = estimateTotalFee({ + ...validParameters, + gasUnits: undefined, + }); + expect(result).toBeUndefined(); + }); + + it("should return undefined when base fee is undefined", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: undefined, + }); + expect(result).toBeUndefined(); + }); + + it("should handle large gas units correctly", function () { + const largeGasUnits = 1000000n; + const result = estimateTotalFee({ + ...validParameters, + gasUnits: largeGasUnits, + }); + // maxFeePerGas = (10 * 2) + 2 = 22 Gwei + // total = 1000000 * 22 Gwei + expect(result).toBe(parseEther("22000000", "gwei")); + }); + + it("should return zero when all parameters are zero", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: 0n, + gasUnits: 0n, + maxPriorityFeePerGas: 0n, + }); + expect(result).toBe(0n); + }); + + it("should handle all minimum values with fallback correctly", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: 0n, + gasUnits: 1n, + maxPriorityFeePerGas: undefined, + }); + // maxFeePerGas = (0 * 2) + 1 Gwei = 1 Gwei (fallback) + // total = 1 * 1 Gwei = 1 Gwei + expect(result).toBe(parseEther("1", "gwei")); + }); + + it("should preserve precision with large numbers and overestimation", function () { + const result = estimateTotalFee({ + ...validParameters, + baseFeePerGas: 100n * parseEther("1", "gwei"), + gasUnits: 500000n, + maxPriorityFeePerGas: 10n * parseEther("1", "gwei"), + overEstimation: 1.75, + }); + // maxFeePerGas = (100 * 2) + 10 = 210 Gwei + // total = 500000 * 210 Gwei * 1.75 + // = 105000000 Gwei * 1.75 = 183750000 Gwei + expect(result).toBe(parseEther("183750000", "gwei")); + }); + + it("should throw when overEstimation is negative", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + overEstimation: -1, + }), + ).toThrow("overEstimation must be a positive finite number"); + }); + + it("should throw when overEstimation is zero", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + overEstimation: 0, + }), + ).toThrow("overEstimation must be a positive finite number"); + }); + + it("should throw when overEstimation is NaN", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + overEstimation: NaN, + }), + ).toThrow("overEstimation must be a positive finite number"); + }); + + it("should throw when overEstimation is Infinity", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + overEstimation: Infinity, + }), + ).toThrow("overEstimation must be a positive finite number"); + }); + + it("should throw when overEstimation is negative Infinity", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + overEstimation: -Infinity, + }), + ).toThrow("overEstimation must be a positive finite number"); + }); + + it("should throw when overEstimation is not a number", function () { + expect(() => + estimateTotalFee({ + ...validParameters, + // @ts-expect-error - testing runtime behavior with invalid type + overEstimation: "1.5", + }), + ).toThrow("overEstimation must be a positive finite number"); + }); +}); diff --git a/src/utils/fees.ts b/src/utils/fees.ts new file mode 100644 index 0000000..732dc70 --- /dev/null +++ b/src/utils/fees.ts @@ -0,0 +1,80 @@ +import { parseEther } from "viem/utils"; + +const DEFAULT_FEE_MULTIPLIER = 2; +const DEFAULT_OVER_ESTIMATION = 1.5; +const DEFAULT_FALLBACK_PRIORITY_FEE = parseEther("1", "gwei"); + +export type EstimateTotalFeeParams = { + baseFeePerGas: bigint | undefined; + maxPriorityFeePerGas: bigint | undefined; + gasUnits?: bigint; + overEstimation?: number; + fallbackPriorityFee?: bigint; +}; + +/** + * Estimates the total transaction fee for an EIP-1559 compatible network. + * + * It uses the base fee and a suggested or fallback maxPriorityFeePerGas to + * calculate a conservative `maxFeePerGas`, and multiplies it by the estimated gas units. + * This function supports a custom `overEstimation` factor to pad the result for safety. + * + * Based on: + * https://github.com/hemilabs/ui-monorepo/blob/694c9fd0e5e8d8deee8f99e7ee5e6d7783020e0e/portal/hooks/useEstimateFees.ts#L56 + * + * @param params - Function parameters. + * @param params.baseFeePerGas - The base fee per gas from the latest block (in wei). + * @param params.maxPriorityFeePerGas - The suggested priority fee per gas (in wei), or undefined if unavailable. + * @param params.gasUnits - Estimated gas units for the transaction, or undefined if unavailable. + * @param params.overEstimation - Optional multiplier to pad the estimated fee for safety. + * @param params.fallbackPriorityFee - Fallback priority fee in wei to use when maxPriorityFeePerGas is unavailable or too low. + * + * @returns {bigint | undefined} Estimated total fee in wei, or undefined if required values are not yet loaded. + */ +export function estimateTotalFee({ + baseFeePerGas, + fallbackPriorityFee = DEFAULT_FALLBACK_PRIORITY_FEE, + gasUnits, + maxPriorityFeePerGas, + overEstimation = DEFAULT_OVER_ESTIMATION, +}: EstimateTotalFeeParams) { + // Validate overEstimation: must be a positive finite number + if ( + typeof overEstimation !== "number" || + !Number.isFinite(overEstimation) || + overEstimation <= 0 + ) { + throw new Error("overEstimation must be a positive finite number"); + } + + // If gas units or base fee are not available, return undefined as we cannot estimate the total fee. + if (gasUnits === undefined || baseFeePerGas === undefined) { + return undefined; + } + + // Normalize the suggested priority fee (in wei): if it's undefined, temporarily + // default to zero and adjust to at least the fallback value in the logic below. + const rawPriorityFeeWei = maxPriorityFeePerGas ?? 0n; + + // Use the estimated priority fee if it's above the fallback, + // otherwise use the fallback to avoid underestimating the fee. + const safePriorityFeeWei = + rawPriorityFeeWei > fallbackPriorityFee + ? rawPriorityFeeWei + : fallbackPriorityFee; + + // Calculate the maxFeePerGas using EIP-1559 strategy: + // maxFeePerGas = baseFee * multiplier + priorityFee + const maxFeePerGasWei = + baseFeePerGas * BigInt(DEFAULT_FEE_MULTIPLIER) + safePriorityFeeWei; + + // Estimate the total fee by multiplying gas units by the max fee per gas, + // and applying an overestimation multiplier (typically 1.0 or 1.5 for safety). + const overEstimationNumerator = BigInt(Math.round(overEstimation * 1000)); + const overEstimationDenominator = 1000n; + const totalFeeEstimate = + (gasUnits * maxFeePerGasWei * overEstimationNumerator) / + overEstimationDenominator; + + return totalFeeEstimate; +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..8c90c2b --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + clearMocks: true, + }, +});