From 5ea8d90a06c9fd4c87f09e88c94bdaf90b6adba4 Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Thu, 2 Jan 2025 09:08:20 +1100 Subject: [PATCH] wip: checkpoint --- pnpm-lock.yaml | 148 +++-- pnpm-workspace.yaml | 2 +- src/core/Porto.ts | 1 + .../__snapshots__/provider.test.ts.snap | 3 + src/core/internal/delegatedAccount.test.ts | 159 +++++ src/core/internal/delegatedAccount.ts | 89 +++ src/core/internal/key.test.ts | 361 +++++++++++ src/core/internal/key.ts | 592 ++++++++++++++++++ src/core/internal/provider.test.ts | 11 + src/package.json | 2 +- test/src/anvil.json | 117 ++++ test/src/anvil.ts | 45 +- test/src/config.ts | 25 + test/vitest.config.ts | 4 + tsconfig.json | 7 +- 15 files changed, 1502 insertions(+), 64 deletions(-) create mode 100644 src/core/internal/__snapshots__/provider.test.ts.snap create mode 100644 src/core/internal/delegatedAccount.test.ts create mode 100644 src/core/internal/delegatedAccount.ts create mode 100644 src/core/internal/key.test.ts create mode 100644 src/core/internal/key.ts create mode 100644 src/core/internal/provider.test.ts create mode 100644 test/src/anvil.json create mode 100644 test/src/config.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70db8a11..35ab384d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,8 +25,8 @@ catalogs: specifier: ^5.5.4 version: 5.6.3 viem: - specifier: ^2.21.51 - version: 2.21.51 + specifier: ^2.22.1 + version: 2.22.1 wagmi: specifier: ^2.12.30 version: 2.12.30 @@ -91,13 +91,13 @@ importers: version: 5.6.3 viem: specifier: 'catalog:' - version: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + version: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) vitest: specifier: ^2.1.8 version: 2.1.8(@types/node@22.9.0)(terser@5.37.0) wagmi: specifier: 'catalog:' - version: 2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) + version: 2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) app: dependencies: @@ -152,10 +152,10 @@ importers: version: 18.3.1(react@18.3.1) viem: specifier: 'catalog:' - version: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + version: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) wagmi: specifier: 'catalog:' - version: 2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) + version: 2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) devDependencies: '@types/react': specifier: 'catalog:' @@ -192,7 +192,7 @@ importers: version: 18.3.1(react@18.3.1) viem: specifier: 'catalog:' - version: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + version: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) devDependencies: '@types/react': specifier: 'catalog:' @@ -1227,6 +1227,10 @@ packages: resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==} engines: {node: ^14.21.3 || >=16} + '@noble/curves@1.7.0': + resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -1235,6 +1239,14 @@ packages: resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.6.0': + resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.6.1': + resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1452,18 +1464,27 @@ packages: '@scure/base@1.1.9': resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + '@scure/base@1.2.1': + resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} + '@scure/bip32@1.4.0': resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} '@scure/bip32@1.5.0': resolution: {integrity: sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==} + '@scure/bip32@1.6.0': + resolution: {integrity: sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==} + '@scure/bip39@1.3.0': resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} '@scure/bip39@1.4.0': resolution: {integrity: sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==} + '@scure/bip39@1.5.0': + resolution: {integrity: sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==} + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -1854,6 +1875,17 @@ packages: zod: optional: true + abitype@1.0.7: + resolution: {integrity: sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -3326,14 +3358,6 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - ox@0.1.2: - resolution: {integrity: sha512-ak/8K0Rtphg9vnRJlbOdaX9R7cmxD2MiSthjWGaQdMk3D7hrAlDoM+6Lxn7hN52Za3vrXfZ7enfke/5WjolDww==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - ox@0.2.2: resolution: {integrity: sha512-QWCyFfVk5hFOhg13SGqRKih5B7EBucrf+Z1dfmN9jJQ8MZdrRx9mbD78JQL5ogSzDT7fcHgyMCaXd/3AWn6xHQ==} peerDependencies: @@ -4298,8 +4322,8 @@ packages: react: optional: true - viem@2.21.51: - resolution: {integrity: sha512-IBZTFoo9cZvMBkFqaJq5G8Ori4IeEDe9AHE5CmOlvNw7ytkC3vdVrJ/APL+V3H4d/5i1FiV331UsckIqQLIM0w==} + viem@2.22.1: + resolution: {integrity: sha512-Dlul3ps87ErRSlAVuLQXQjquk0ECy/BCKATEErwHkVd0KQZvj80T5BUU0cDABo4axNF3+78Q060y6VFiT0+SqQ==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -4966,7 +4990,7 @@ snapshots: '@coinbase/wallet-sdk@4.2.1(@types/node@22.9.0)(terser@5.37.0)': dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.6.1 clsx: 1.2.1 eventemitter3: 5.0.1 preact: 10.24.3 @@ -5503,7 +5527,7 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.6.1 '@scure/base': 1.1.9 '@types/debug': 4.1.12 debug: 4.3.7 @@ -5517,7 +5541,7 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.6.1 '@scure/base': 1.1.9 '@types/debug': 4.1.12 debug: 4.3.7 @@ -5608,10 +5632,18 @@ snapshots: dependencies: '@noble/hashes': 1.5.0 + '@noble/curves@1.7.0': + dependencies: + '@noble/hashes': 1.6.0 + '@noble/hashes@1.4.0': {} '@noble/hashes@1.5.0': {} + '@noble/hashes@1.6.0': {} + + '@noble/hashes@1.6.1': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5785,7 +5817,7 @@ snapshots: '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.22.2 - viem: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) transitivePeerDependencies: - bufferutil - typescript @@ -5796,6 +5828,8 @@ snapshots: '@scure/base@1.1.9': {} + '@scure/base@1.2.1': {} + '@scure/bip32@1.4.0': dependencies: '@noble/curves': 1.4.2 @@ -5808,6 +5842,12 @@ snapshots: '@noble/hashes': 1.5.0 '@scure/base': 1.1.9 + '@scure/bip32@1.6.0': + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 + '@scure/bip39@1.3.0': dependencies: '@noble/hashes': 1.4.0 @@ -5818,6 +5858,11 @@ snapshots: '@noble/hashes': 1.5.0 '@scure/base': 1.1.9 + '@scure/bip39@1.5.0': + dependencies: + '@noble/hashes': 1.6.1 + '@scure/base': 1.2.1 + '@sec-ant/readable-stream@0.4.1': {} '@sindresorhus/is@4.6.0': {} @@ -6124,7 +6169,7 @@ snapshots: picocolors: 1.1.1 picomatch: 3.0.1 prettier: 3.3.3 - viem: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) zod: 3.23.8 optionalDependencies: typescript: 5.6.3 @@ -6132,16 +6177,16 @@ snapshots: - bufferutil - utf-8-validate - '@wagmi/connectors@5.3.8(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8)': + '@wagmi/connectors@5.3.8(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8)': dependencies: '@coinbase/wallet-sdk': 4.2.1(@types/node@22.9.0)(terser@5.37.0) '@metamask/sdk': 0.30.1(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.4(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) - '@wagmi/core': 2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@wagmi/core': 2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) '@walletconnect/ethereum-provider': 2.17.0(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -6182,11 +6227,11 @@ snapshots: - utf-8-validate - zod - '@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': + '@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.6.3) - viem: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) zustand: 5.0.0(@types/react@18.3.12)(react@18.3.1)(use-sync-external-store@1.2.0(react@18.3.1)) optionalDependencies: '@tanstack/query-core': 5.59.20 @@ -6592,6 +6637,11 @@ snapshots: typescript: 5.6.3 zod: 3.23.8 + abitype@1.0.7(typescript@5.6.3)(zod@3.23.8): + optionalDependencies: + typescript: 5.6.3 + zod: 3.23.8 + acorn@8.14.0: {} agent-base@7.1.3: {} @@ -7049,8 +7099,8 @@ snapshots: dependencies: '@ecies/ciphers': 0.2.1(@noble/ciphers@1.0.0) '@noble/ciphers': 1.0.0 - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 electron-to-chromium@1.5.56: {} @@ -8110,20 +8160,6 @@ snapshots: outdent@0.5.0: {} - ox@0.1.2(typescript@5.6.3)(zod@3.23.8): - dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 - '@scure/bip32': 1.5.0 - '@scure/bip39': 1.4.0 - abitype: 1.0.6(typescript@5.6.3)(zod@3.23.8) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.6.3 - transitivePeerDependencies: - - zod - ox@0.2.2(typescript@5.6.3)(zod@3.23.8): dependencies: '@adraffy/ens-normalize': 1.11.0 @@ -9094,15 +9130,15 @@ snapshots: '@types/react': 18.3.12 react: 18.3.1 - viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): + viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8): dependencies: - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 - '@scure/bip32': 1.5.0 - '@scure/bip39': 1.4.0 - abitype: 1.0.6(typescript@5.6.3)(zod@3.23.8) + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(typescript@5.6.3)(zod@3.23.8) isows: 1.0.6(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - ox: 0.1.2(typescript@5.6.3)(zod@3.23.8) + ox: 0.6.0(typescript@5.6.3)(zod@3.23.8) webauthn-p256: 0.0.10 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: @@ -9175,14 +9211,14 @@ snapshots: - supports-color - terser - wagmi@2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8): + wagmi@2.12.30(@tanstack/query-core@5.59.20)(@tanstack/react-query@5.59.20(react@18.3.1))(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8): dependencies: '@tanstack/react-query': 5.59.20(react@18.3.1) - '@wagmi/connectors': 5.3.8(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) - '@wagmi/core': 2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) + '@wagmi/connectors': 5.3.8(@types/node@22.9.0)(@types/react@18.3.12)(@upstash/redis@1.34.3)(@wagmi/core@2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)))(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(terser@5.37.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) + '@wagmi/core': 2.14.5(@tanstack/query-core@5.59.20)(@types/react@18.3.12)(react@18.3.1)(typescript@5.6.3)(use-sync-external-store@1.2.0(react@18.3.1))(viem@2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8)) react: 18.3.1 use-sync-external-store: 1.2.0(react@18.3.1) - viem: 2.21.51(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) + viem: 2.22.1(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)(zod@3.23.8) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -9235,8 +9271,8 @@ snapshots: webauthn-p256@0.0.10: dependencies: - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 webextension-polyfill@0.10.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f873e200..e79c45ce 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,5 +11,5 @@ catalog: react: "^18.3.1" react-dom: "^18.3.1" typescript: "^5.5.4" - viem: "^2.21.51" + viem: "^2.22.1" wagmi: "^2.12.30" diff --git a/src/core/Porto.ts b/src/core/Porto.ts index 730d8489..44a3cfcd 100644 --- a/src/core/Porto.ts +++ b/src/core/Porto.ts @@ -74,6 +74,7 @@ export function create(config: Config | undefined = {}): Porto { return createClient({ chain, transport: (transports as Record)[chain.id]!, + pollingInterval: 1_000, }) }, get delegation() { diff --git a/src/core/internal/__snapshots__/provider.test.ts.snap b/src/core/internal/__snapshots__/provider.test.ts.snap new file mode 100644 index 00000000..6af1dcda --- /dev/null +++ b/src/core/internal/__snapshots__/provider.test.ts.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`default 1`] = `"0x6080604052600436106101c5575f3560e01c806384b0196e116100f6578063bf53096911610094578063e9ae5c5311610063578063e9ae5c53146105f9578063f0c60f1a1461060c578063fac750e014610620578063ff619c6b14610634576101cc565b8063bf5309691461054e578063cb4774c41461056d578063cebfe3361461058e578063d03c7914146105ad576101cc565b8063a2e2f930116100d0578063a2e2f930146104d2578063a840fe49146104f1578063b70e36f014610510578063b75c7dc61461052f576101cc565b806384b0196e1461045957806394430fa5146104805780639c42fb59146104a3576101cc565b80632f3f30c711610163578063515c9d6d1161013d578063515c9d6d146103cb57806360d2f33d146103eb5780636ae269cc1461041e5780636fd914541461043a576101cc565b80632f3f30c71461037857806335058501146103925780634223b5c2146103ac576101cc565b8063136a12f71161019f578063136a12f7146102ab5780631626ba7e146102cc5780631a912f3e1461030457806320606b7014610345576101cc565b80630cef73b41461020557806311a86fd61461024057806312aaac701461027f576101cc565b366101cc57005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a02821417156101f757806020526020603cf35b50633c10b94e5f526004601cfd5b348015610210575f80fd5b5061022461021f366004612068565b610653565b6040805192151583526020830191909152015b60405180910390f35b34801561024b575f80fd5b5061026773323232323232323232323232323232323232323281565b6040516001600160a01b039091168152602001610237565b34801561028a575f80fd5b5061029e6102993660046120b0565b61066d565b6040516102379190612109565b3480156102b6575f80fd5b506102ca6102c536600461218b565b61075d565b005b3480156102d7575f80fd5b506102eb6102e6366004612068565b610868565b6040516001600160e01b03199091168152602001610237565b34801561030f575f80fd5b506103377f84fa2cf05cd88e992eae77e851af68a4ee278dcff6ef504e487a55b3baadfbe581565b604051908152602001610237565b348015610350575f80fd5b506103377f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b348015610383575f80fd5b506102eb630707070760e51b81565b34801561039d575f80fd5b506102eb631919191960e11b81565b3480156103b7575f80fd5b5061029e6103c63660046120b0565b61089b565b3480156103d6575f80fd5b506103375f8051602061266f83398151915281565b3480156103f6575f80fd5b506103377fe530e62dece51c9bec26701907051ddc8420a62f028096eeb58263193e84e04981565b348015610429575f80fd5b50686d3d4e7fb92a52381554610337565b348015610445575f80fd5b506103376104543660046121e5565b6108d9565b348015610464575f80fd5b5061046d610a2c565b604051610237979695949392919061225a565b34801561048b575f80fd5b506102676fac830f1181f6aab6862e71edc248941c81565b3480156104ae575f80fd5b506104c26104bd3660046122f0565b610a8d565b6040519015158152602001610237565b3480156104dd575f80fd5b506104c26104ec3660046120b0565b610ad1565b3480156104fc575f80fd5b5061033761050b3660046123e2565b610af9565b34801561051b575f80fd5b506102ca61052a3660046120b0565b610b32565b34801561053a575f80fd5b506102ca6105493660046120b0565b610b5d565b348015610559575f80fd5b506102ca610568366004612491565b610bb2565b348015610578575f80fd5b50610581610c56565b60405161023791906124d0565b348015610599575f80fd5b506103376105a83660046123e2565b610c6f565b3480156105b8575f80fd5b506104c26105c73660046120b0565b690100000000007821000160b09190911c69ffff00000000ffffffff1690811460011b600160481b9190911417151590565b6102ca610607366004612068565b610cd7565b348015610617575f80fd5b50610337610d60565b34801561062b575f80fd5b50610337610df3565b34801561063f575f80fd5b506104c261064e3660046124e2565b610e06565b5f806106618585855f611099565b91509150935093915050565b604080516080810182525f80825260208201819052918101919091526060808201525f828152686d3d4e7fb92a523817602052604081206106ad906112bb565b905080515f036106d05760405163395ed8c160e21b815260040160405180910390fd5b8051600619015f6106e48383016020015190565b60d881901c855260c881901c915060d01c60ff166002811115610709576107096120c7565b8460200190600281111561071f5761071f6120c7565b90816002811115610732576107326120c7565b90525060ff81161515604085015261074f83838151811082025290565b606085015250919392505050565b33301461077c576040516282b42960e81b815260040160405180910390fd5b8361079a57604051638707510560e01b815260040160405180910390fd5b6107a48383611321565b156107cf576107b28461134b565b6107cf576040516303a6f8c760e21b815260040160405180910390fd5b5f82815260188490526004859052603881208152683c149ebf7b8e6c5e226020818152604092839020805485151560ff19909116811790915583518881526001600160a01b038816928101929092526001600160e01b03198616828501526060820152915190917f7eb91b8ac56c0864a4e4f5598082d140d04bed1a4dd62a41d605be2430c494e1919081900360800190a15050505050565b5f806108778585856001611099565b509050806108895763ffffffff61088f565b631626ba7e5b60e01b95945050505050565b604080516080810182525f80825260208201819052918101919091526060808201526108d3610299686d3d4e7fb92a5238168461135f565b92915050565b5f806108f58460408051828152600190920160051b8201905290565b90505f5b848110156109b857368686838181106109145761091461253a565b9050602002810190610926919061254e565b90506109ae8261099f7f84fa2cf05cd88e992eae77e851af68a4ee278dcff6ef504e487a55b3baadfbe561095d602086018661256c565b6001600160a01b0316602086013561098061097b6040890189612587565b6113a8565b6040805194855260208501939093529183015260608201526080902090565b600190910160051b8501528390565b50506001016108f9565b50610a23610a1e7fe530e62dece51c9bec26701907051ddc8420a62f028096eeb58263193e84e0496109f284805160051b60209091012090565b686d3d4e7fb92a5238155460408051938452602084019290925290820187905260608201526080902090565b6113b9565b95945050505050565b600f60f81b6060805f808083610a7b604080518082018252600a8152692232b632b3b0ba34b7b760b11b60208083019190915282518084019093526005835264302e302e3160d81b9083015291565b97989097965046955030945091925090565b5f336fac830f1181f6aab6862e71edc248941c14610abd576040516282b42960e81b815260040160405180910390fd5b610ac88333846114cf565b50600192915050565b600881901c5f908152686d3d4e7fb92a523814602052604081205460ff83161c6001166108d3565b5f6108d382602001516002811115610b1357610b136120c7565b60ff168360600151805190602001205f1c5f9182526020526040902090565b333014610b51576040516282b42960e81b815260040160405180910390fd5b610b5a816114f7565b50565b333014610b7c576040516282b42960e81b815260040160405180910390fd5b610b8581611553565b60405181907fe5af7daed5ab2a2dc5f98d53619f05089c0c14d11a6621f6b906a2366c9a7ab3905f90a250565b333014610bd1576040516282b42960e81b815260040160405180910390fd5b610c1982828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610c1392506112ae915050565b906115a7565b7faec6ef4baadc9acbdf52442522dfffda03abe29adba8d4af611bcef4cbe0c9ad8282604051610c4a9291906125ca565b60405180910390a15050565b6060610c6a686d3d4e7fb92a5238136112bb565b905090565b5f333014610c8f576040516282b42960e81b815260040160405180910390fd5b610c98826115ff565b9050807f3d3a48be5a98628ecf98a6201185102da78bbab8f63a4b2d6b9eef354f5131f583604051610cca9190612109565b60405180910390a2919050565b690100000000007821000160b084901c69ffff00000000ffffffff1690811460011b600160481b9190911417365f818184610d1957637f1812755f526004601cfd5b5085358087016020810194503592505f90604011600286141115610d47575050602080860135860190810190355b610d5688888887878787611674565b5050505050505050565b5f333014610d80576040516282b42960e81b815260040160405180910390fd5b50686d3d4e7fb92a523815805460408051828152426020808301919091523382840152606090912063ffffffff169092019283905580518381529051686d3d4e7fb92a523813927f7328006ebae4716b8db9514af69091e0ad74bec61dfdc256ed5446b234aa5424928290030190a15090565b5f610c6a686d3d4e7fb92a52381661178b565b5f84610e1457506001611091565b683c149ebf7b8e6c5e22631919191960e11b60048410610e32575083355b83610e415750630707070760e51b5b610e4b8682611321565b15610e6757610e598761134b565b610e67575f92505050611091565b5f818152601887905260048890526038812081526020839052604090205460ff1615610e9857600192505050611091565b5f81815273323232323232323232323232323232323232323260185260048890526038812081526020839052604090205460ff1615610edc57600192505050611091565b5f81815260188790525f8051602061266f8339815191526004526038812081526020839052604090205460ff1615610f1957600192505050611091565b5f8181527332323232323232323232323232323232323232326018525f8051602061266f8339815191526004526038812081526020839052604090205460ff1615610f6957600192505050611091565b631919191960e11b5f908152601887905260048890526038812081526020839052604090205460ff1615610fa257600192505050611091565b631919191960e11b5f90815273323232323232323232323232323232323232323260185260048890526038812081526020839052604090205460ff1615610fee57600192505050611091565b631919191960e11b5f90815260188790525f8051602061266f8339815191526004526038812081526020839052604090205460ff161561103357600192505050611091565b631919191960e11b5f9081527332323232323232323232323232323232323232326018525f8051602061266f8339815191526004526038812081526020839052604090205460ff161561108b57600192505050611091565b5f925050505b949350505050565b5f80604184146040851417156110c957306110b58787876117d7565b6001600160a01b03161491505f90506112a5565b60218410156110dc57505f9050806112a5565b506020198381018481118186180281189486019182013591601f19013560ff161561110d5761110a8761185f565b96505b505f6111188261066d565b6040810151909150158415151615611133575f9250506112a5565b805164ffffffffff164281109015151615611151575f9250506112a5565b5f81602001516002811115611168576111686120c7565b036111c3575f80603f8711883581029060208a013502915091505f806111a7856060015180516020820151604090920151603f90911191820292910290565b915091506111b88b8585858561187d565b9650505050506112a3565b6001816020015160028111156111db576111db6120c7565b0361126057606081810151805160208083015160409384015184518084018e9052855180820385018152601f8d018590049094028101870186529485018b8152603f9490941091820295910293611257935f92611250928e918e918291018382808284375f9201919091525061190f92505050565b85856119f3565b945050506112a3565b600281602001516002811115611278576112786120c7565b036112a3576112a0816060015180602001905181019061129891906125f8565b888888611b12565b92505b505b94509492505050565b686d3d4e7fb92a52381390565b60405181546020820190600881901c5f8260ff8417146112e957505080825260ff8116601f8082111561130b575b855f5260205f205b8160051c810154828601526020820191508282106112f157505b508084525f920191825250602001604052919050565b5f63e9ae5c5360e01b6001600160e01b0319831614306001600160a01b03851614165b9392505050565b5f6113558261066d565b6040015192915050565b6318fb58646004525f8281526024902081015468fbb67fda52d4bfb8bf811415026113898361178b565b82106108d357604051634e23d03560e01b815260040160405180910390fd5b5f8183604051375060405120919050565b7f06012d2aedbb397c1914278c3206cec06702f79ceb18361e1ddb2fcc068c324f7f0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa330147f0000000000000000000000000000000000000000000000000000000000007a694614166114ac5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f6c157b110f3bc0280dba8ae624dab3ba623d9bab8692057c96d59c9188d52cb260208201527fae209a0b48f21c054280f2455d32cf309387644879d9acbd8ffc1991638118859181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b6001600160a01b0383166114ec576114e78282611be0565b505050565b6114e7838383611bf9565b600881901c5f908152686d3d4e7fb92a523814602052604090208054600160ff84161b1790556040518181527f4d9dbebf1d909894d9c26fe228c27cec643b2cb490124e5b658f4edd203c20c19060200160405180910390a150565b5f818152686d3d4e7fb92a5238176020526040812055686d3d4e7fb92a523813611586686d3d4e7fb92a52381683611c43565b6115a35760405163395ed8c160e21b815260040160405180910390fd5b5050565b80518060081b60ff175f60fe83116115d0575050601f8281015160081b821790808311156115f7575b60208401855f5260205f205b828201518360051c8201556020830192508483106115dc5750505b509092555050565b5f61160982610af9565b90505f686d3d4e7fb92a5238136060840151845160208087015160408089015190519596506116609561163e95949301612613565b60408051601f198184030181529181525f8581526004850160205220906115a7565b61166d6003820183611d4f565b5050919050565b6fac830f1181f6aab6862e71edc248941b1933016116cc5760408110156116ae576040516355fe73fd60e11b815260040160405180910390fd5b6116b88235611e6a565b6116c784846020850135611e91565b611782565b806116fb573330146116f0576040516282b42960e81b815260040160405180910390fd5b6116c784845f611e91565b602081101561171d576040516355fe73fd60e11b815260040160405180910390fd5b813561172881611e6a565b5f806117526117388888866108d9565b602080871081881802188088019080880390881102610653565b9150915081611773576040516282b42960e81b815260040160405180910390fd5b61177e878783611e91565b5050505b50505050505050565b6318fb58646004525f818152602481208019548060011c92508061166d5781545f93501561166d5760019250828201541561166d5760029250828201541561166d575060039392505050565b5f60405182604081146117f25760418114611819575061184a565b60208581013560ff81901c601b0190915285356040526001600160ff1b031660605261182a565b60408501355f1a6020526040856040375b50845f526020600160805f60015afa5191505f606052806040523d611857575b638baa579f5f526004601cfd5b509392505050565b5f815f526020600160205f60025afa5190503d61187857fe5b919050565b5f6040518681528560208201528460408201528360608201528260808201525f805260205f60a0836101005afa503d6118da5760203d60a0836dcb83347beb24c695bbb85dbe99b75afa503d6118da5763d0d5039b3d526004601cfd5b505f516001147f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8851110905095945050505050565b6040805160c0810182526060808252602082018190525f92820183905281018290526080810182905260a0810191909152815160c081106119ed5760208301818101818251018281108260c0830111171561196c575050506119ed565b808151019250806020820151018181108382111782851084861117171561199657505050506119ed565b82815160208301011183855160208701011117156119b757505050506119ed565b8386528060208701525060408101516040860152606081015160608601526080810151608086015260a081015160a08601525050505b50919050565b5f805f611a0288600180611edf565b905060208601518051602082019150604088015160608901518451600d81016c1131b430b63632b733b2911d1160991b60981c8752848482011060228286890101515f1a14168160138901208286890120141685846014011085851760801c1074113a3cb832911d113bb2b130baba34371733b2ba1160591b60581c8589015160581c14161698505080865250505087515189151560021b600117808160218c5101511614602083118816169650508515611ae657602089510181810180516020600160208601856020868a8c60025afa60011b5afa51915295503d9050611ae657fe5b5050508215611b0757611b048287608001518860a00151888861187d565b92505b505095945050505050565b5f6001600160a01b03851615611091576040518260408114611b3c5760418114611b635750611b98565b60208581013560ff81901c601b0190915285356040526001600160ff1b0316606052611b74565b60408501355f1a6020526040856040375b50845f526020600160805f60015afa5180871860601b3d119250505f606052806040525b81611bd757631626ba7e60e01b80825285600483015260248201604081528460448401528486606485013760208160648701858b5afa90519091141691505b50949350505050565b5f385f3884865af16115a35763b12d13eb5f526004601cfd5b816014528060345263a9059cbb60601b5f5260205f604460105f875af18060015f511416611c3957803d853b151710611c39576390b8ec185f526004601cfd5b505f603452505050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf8303611c705763f5a267f15f526004601cfd5b82611c825768fbb67fda52d4bfb8bf92505b80195480611ceb576001925083825403611caf5760018201805483556002830180549091555f9055611d47565b83600183015403611ccd5760028201805460018401555f9055611d47565b83600283015403611ce3575f6002830155611d47565b5f9250611d47565b81602052835f5260405f20805480611d04575050611d47565b60018360011c039250826001820314611d33578284015480600183038601555f84860155805f52508060405f20555b5060018260011b178319555f815550600192505b505092915050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf8303611d7c5763f5a267f15f526004601cfd5b82611d8e5768fbb67fda52d4bfb8bf92505b8019548160205280611e3257815480611dae578483556001935050611d47565b848103611dbb5750611d47565b600183015480611dd657856001850155600194505050611d47565b858103611de4575050611d47565b600284015480611e005786600286015560019550505050611d47565b868103611e0f57505050611d47565b5f9283526040808420600190559183528183206002905582529020600390555060075b835f5260405f208054611e6157600191821c8381018690558083019182905590821b8217831955909250611d47565b50505092915050565b611e7381610ad1565b15610b5157604051633ab3447f60e11b815260040160405180910390fd5b600582901b5f5b818114611ed8576020818101918601358601803580153002179181810135916040810135019081019035611ecf848484848b611fd0565b50505050611e98565b5050505050565b606083518015611857576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f526020830181810183886020010180515f82525b60038a0199508951603f8160121c16515f53603f81600c1c1651600153603f8160061c1651600253603f811651600353505f518452600484019350828410611f5a579052602001604052613d3d60f01b60038406600204808303919091525f861515909102918290035290038252509392505050565b611fdc81868585610e06565b611ff8576040516282b42960e81b815260040160405180910390fd5b611ed88585858585604051828482375f388483888a5af161201b573d5f823e3d81fd5b505050505050565b5f8083601f840112612033575f80fd5b50813567ffffffffffffffff81111561204a575f80fd5b602083019150836020828501011115612061575f80fd5b9250929050565b5f805f6040848603121561207a575f80fd5b83359250602084013567ffffffffffffffff811115612097575f80fd5b6120a386828701612023565b9497909650939450505050565b5f602082840312156120c0575f80fd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6020815264ffffffffff82511660208201525f60208301516003811061213d57634e487b7160e01b5f52602160045260245ffd5b80604084015250604083015115156060830152606083015160808084015261109160a08401826120db565b6001600160a01b0381168114610b5a575f80fd5b80358015158114611878575f80fd5b5f805f806080858703121561219e575f80fd5b8435935060208501356121b081612168565b925060408501356001600160e01b0319811681146121cc575f80fd5b91506121da6060860161217c565b905092959194509250565b5f805f604084860312156121f7575f80fd5b833567ffffffffffffffff81111561220d575f80fd5b8401601f8101861361221d575f80fd5b803567ffffffffffffffff811115612233575f80fd5b8660208260051b8401011115612247575f80fd5b6020918201979096509401359392505050565b60ff60f81b8816815260e060208201525f61227860e08301896120db565b828103604084015261228a81896120db565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b818110156122df5783518352602093840193909201916001016122c1565b50909b9a5050505050505050505050565b5f8060408385031215612301575f80fd5b823561230c81612168565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156123515761235161231a565b60405290565b5f82601f830112612366575f80fd5b813567ffffffffffffffff8111156123805761238061231a565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123af576123af61231a565b6040528181528382016020018510156123c6575f80fd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156123f2575f80fd5b813567ffffffffffffffff811115612408575f80fd5b820160808185031215612419575f80fd5b61242161232e565b813564ffffffffff81168114612435575f80fd5b8152602082013560038110612448575f80fd5b60208201526124596040830161217c565b6040820152606082013567ffffffffffffffff811115612477575f80fd5b61248386828501612357565b606083015250949350505050565b5f80602083850312156124a2575f80fd5b823567ffffffffffffffff8111156124b8575f80fd5b6124c485828601612023565b90969095509350505050565b602081525f61134460208301846120db565b5f805f80606085870312156124f5575f80fd5b84359350602085013561250781612168565b9250604085013567ffffffffffffffff811115612522575f80fd5b61252e87828801612023565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112612562575f80fd5b9190910192915050565b5f6020828403121561257c575f80fd5b813561134481612168565b5f808335601e1984360301811261259c575f80fd5b83018035915067ffffffffffffffff8211156125b6575f80fd5b602001915036819003821315612061575f80fd5b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f60208284031215612608575f80fd5b815161134481612168565b5f85518060208801845e60d886901b6001600160d81b0319169083019081526003851061264e57634e487b7160e01b5f52602160045260245ffd5b60f894851b600582015292151590931b600683015250600701939250505056fe3232323232323232323232323232323232323232323232323232323232323232a2646970667358221220fedfc3184b2b333b20591e8e82d687d62f41e28fa92d349d78b640fb4d41df5764736f6c634300081a0033"`; diff --git a/src/core/internal/delegatedAccount.test.ts b/src/core/internal/delegatedAccount.test.ts new file mode 100644 index 00000000..92519f65 --- /dev/null +++ b/src/core/internal/delegatedAccount.test.ts @@ -0,0 +1,159 @@ +import { AbiFunction, P256, Secp256k1, Value } from 'ox' +import { privateKeyToAccount } from 'viem/accounts' +import { getBalance, readContract, setBalance } from 'viem/actions' +import { + type SignAuthorizationParameters, + signAuthorization, +} from 'viem/experimental' +import { describe, expect, test } from 'vitest' + +import { porto } from '../../../test/src/config.js' +import * as DelegatedAccount from './delegatedAccount.js' +import { delegationAbi } from './generated.js' +import * as Key from './key.js' + +const state = porto._internal.store.getState() +const client = state.client.extend(() => ({ mode: 'anvil' })) + +async function setup( + parameters: { + delegate?: SignAuthorizationParameters['delegate'] | undefined + } = {}, +) { + const { delegate } = parameters + + const privateKey = Secp256k1.randomPrivateKey() + const eoa = privateKeyToAccount(privateKey) + + await setBalance(client, { + address: eoa.address, + value: Value.fromEther('2'), + }) + + const authorization = await signAuthorization(client, { + account: eoa, + contractAddress: state.delegation, + delegate, + }) + + return { authorization, eoa } +} + +describe('authorize', () => { + test('sender = EOA, keysToAuthorize = [P256], executor = EOA', async () => { + const { authorization, eoa } = await setup() + + const key = Key.fromP256({ + privateKey: P256.randomPrivateKey(), + role: 'admin', + }) + + const account = DelegatedAccount.from({ + address: eoa.address, + keys: [key], + }) + + await DelegatedAccount.execute(client, { + account, + authorizationList: [authorization], + executor: eoa, + calls: [ + { + data: AbiFunction.encodeData( + AbiFunction.fromAbi(delegationAbi, 'authorize'), + [Key.serialize(key)], + ), + to: account.address, + }, + ], + }) + + const serializedKey = await readContract(client, { + abi: delegationAbi, + address: account.address, + functionName: 'keyAt', + args: [0n], + }) + + expect(Key.deserialize(serializedKey)).toEqual({ ...key, sign: undefined }) + }) +}) + +describe('execute', () => { + test.skip('sender = EOA, executor = JSON-RPC', async () => { + const { authorization, eoa } = await setup({ delegate: true }) + + const alice = privateKeyToAccount(Secp256k1.randomPrivateKey()) + const bob = privateKeyToAccount(Secp256k1.randomPrivateKey()) + + const balances_before = await Promise.all([ + getBalance(client, { address: eoa.address }), + getBalance(client, { address: alice.address }), + getBalance(client, { address: bob.address }), + ]) + + expect(balances_before[0]).toEqual(Value.fromEther('2')) + expect(balances_before[1]).toEqual(Value.fromEther('0')) + expect(balances_before[2]).toEqual(Value.fromEther('0')) + + await DelegatedAccount.execute(client, { + account: eoa, + authorizationList: [authorization], + executor: null, + calls: [ + { to: alice.address, value: Value.fromEther('1') }, + { to: bob.address, value: Value.fromEther('0.5') }, + ], + }) + + const balances_after = await Promise.all([ + getBalance(client, { address: eoa.address }), + getBalance(client, { address: alice.address }), + getBalance(client, { address: bob.address }), + ]) + + expect(balances_after[0]).not.toBeGreaterThan( + balances_before[0] - Value.fromEther('1'), + ) + expect(balances_after[1]).toEqual(Value.fromEther('1')) + expect(balances_after[2]).toEqual(Value.fromEther('0.5')) + }) + + test('sender = EOA, executor = EOA', async () => { + const { authorization, eoa } = await setup() + + const alice = privateKeyToAccount(Secp256k1.randomPrivateKey()) + const bob = privateKeyToAccount(Secp256k1.randomPrivateKey()) + + const balances_before = await Promise.all([ + getBalance(client, { address: eoa.address }), + getBalance(client, { address: alice.address }), + getBalance(client, { address: bob.address }), + ]) + + expect(balances_before[0]).toEqual(Value.fromEther('2')) + expect(balances_before[1]).toEqual(Value.fromEther('0')) + expect(balances_before[2]).toEqual(Value.fromEther('0')) + + await DelegatedAccount.execute(client, { + account: eoa, + authorizationList: [authorization], + calls: [ + { to: alice.address, value: Value.fromEther('1') }, + { to: bob.address, value: Value.fromEther('0.5') }, + ], + }) + + const balances_after = await Promise.all([ + getBalance(client, { address: eoa.address }), + getBalance(client, { address: alice.address }), + getBalance(client, { address: bob.address }), + ]) + + expect(balances_after[0]).not.toBeGreaterThan( + balances_before[0] - Value.fromEther('1'), + ) + expect(balances_after[1]).toEqual(Value.fromEther('1')) + expect(balances_after[2]).toEqual(Value.fromEther('0.5')) + }) +}) diff --git a/src/core/internal/delegatedAccount.ts b/src/core/internal/delegatedAccount.ts new file mode 100644 index 00000000..7bfd9fd2 --- /dev/null +++ b/src/core/internal/delegatedAccount.ts @@ -0,0 +1,89 @@ +import type * as Address from 'ox/Address' +import * as Hex from 'ox/Hex' +import type { Account, Chain, Client, Transport } from 'viem' +import { + type ExecuteParameters, + type ExecuteReturnType, + execute as execute_viem, +} from 'viem/experimental/erc7821' + +import { readContract } from 'viem/actions' + +import { delegationAbi } from './generated.js' +import type * as Key from './key.js' + +/** A delegated account. */ +export type DelegatedAccount = { + address: Address.Address + keys: readonly Key.Key[] + label?: string | undefined +} + +/** + * Executes a set of calls on a delegated account. + * + * @param client - Client. + * @param parameters - Execution parameters. + * @returns Transaction hash. + */ +export async function execute< + const calls extends readonly unknown[], + chain extends Chain | undefined, +>( + client: Client, + parameters: execute.Parameters, +): Promise { + const { account, executor, ...rest } = parameters + try { + return await execute_viem(client, { + ...rest, + address: account.address, + account: typeof executor === 'undefined' ? account : executor, + } as ExecuteParameters) + } catch (error) { + // biome-ignore lint/complexity/noUselessCatch: TODO: Handle contract errors + throw error + } +} + +export declare namespace execute { + export type Parameters< + calls extends readonly unknown[] = readonly unknown[], + chain extends Chain | undefined = Chain | undefined, + > = Omit< + ExecuteParameters, + 'account' | 'address' | 'opData' + > & { + /** + * The delegated account to execute the calls on. + * + * - `DelegatedAccount`: account that was instantiated with `Delegation.create` or `Delegation.from`. + * - `Account`: Viem account that has delegated to Porto. + */ + account: DelegatedAccount | Account + /** + * The executor of the execute transaction. + * + * - `Account`: execution will be attempted with the specified account. + * - `null`: the transaction will be filled by the JSON-RPC server. + * - `undefined`: execution will be attempted with the `account` value. + */ + executor?: Account | undefined | null + /** + * The index of the key to use on the delegated account to sign the execution. + */ + keyIndex?: number | undefined + } + + export type ReturnType = ExecuteReturnType +} + +/** + * Instantiates a delegated account. + * + * @param account - Account to instantiate. + * @returns An instantiated delegated account. + */ +export function from(account: DelegatedAccount): DelegatedAccount { + return account +} diff --git a/src/core/internal/key.test.ts b/src/core/internal/key.test.ts new file mode 100644 index 00000000..b66f01f7 --- /dev/null +++ b/src/core/internal/key.test.ts @@ -0,0 +1,361 @@ +import { Bytes, Secp256k1, WebAuthnP256, WebCryptoP256 } from 'ox' +import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest' + +import * as Key from './key.js' + +describe('createP256', () => { + test('default', () => { + const key = Key.createP256({ + role: 'admin', + }) + + const { publicKey, ...rest } = key + + expect(publicKey).toBeDefined() + expect(rest).toMatchInlineSnapshot(` + { + "expiry": 0, + "role": "admin", + "sign": [Function], + "type": "p256", + } + `) + }) +}) + +describe('createSecp256k1', () => { + test('default', () => { + const key = Key.createSecp256k1({ + role: 'admin', + }) + + const { publicKey, ...rest } = key + + expect(publicKey).toBeDefined() + expect(rest).toMatchInlineSnapshot(` + { + "expiry": 0, + "role": "admin", + "sign": [Function], + "type": "secp256k1", + } + `) + }) +}) + +describe('createWebAuthnP256', () => { + beforeAll(() => { + vi.stubGlobal('window', { + location: { + hostname: 'https://example.com', + }, + document: { + title: 'My Website', + }, + }) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + + test('default', async () => { + const key = await Key.createWebAuthnP256({ + createFn() { + return Promise.resolve({ + id: 'm1-bMPuAqpWhCxHZQZTT6e-lSPntQbh3opIoGe7g4Qs', + response: { + getPublicKey() { + return [ + 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, + 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 171, 137, 20, 0, 20, 15, 196, + 248, 233, 65, 206, 15, 249, 14, 65, 157, 233, 71, 10, 202, 202, + 97, 59, 189, 113, 122, 71, 117, 67, 80, 49, 167, 216, 132, 49, + 142, 145, 159, 211, 179, 229, 166, 49, 216, 102, 216, 163, 128, + 180, 64, 99, 231, 15, 12, 56, 30, 225, 110, 6, 82, 247, 249, + 117, 84, + ] + }, + }, + } as any) + }, + label: 'test', + role: 'admin', + userId: Bytes.from('0x0000000000000000000000000000000000000000'), + }) + + const { publicKey, ...rest } = key + + expect(publicKey).toBeDefined() + expect(rest).toMatchInlineSnapshot(` + { + "expiry": 0, + "role": "admin", + "sign": [Function], + "type": "webauthn-p256", + } + `) + }) +}) + +describe('createWebCryptoP256', () => { + test('default', async () => { + const key = await Key.createWebCryptoP256({ + role: 'admin', + }) + + const { publicKey, ...rest } = key + + expect(publicKey).toBeDefined() + expect(rest).toMatchInlineSnapshot(` + { + "expiry": 0, + "role": "admin", + "sign": [Function], + "type": "p256", + } + `) + }) +}) + +describe('deserialize', () => { + test('default', () => { + const key = Key.fromP256({ + privateKey: + '0x59ff6b8de3b3b39e94b6f9fc0590cf4e3eaa9b6736e6a49c9a6b324c4f58cb9f', + role: 'admin', + }) + const serialized = Key.serialize(key) + const deserialized = Key.deserialize(serialized) + + expect(deserialized).toEqual({ + ...key, + sign: undefined, + }) + }) +}) + +describe('from', () => { + test('default', () => { + const publicKey = Secp256k1.getPublicKey({ + privateKey: Secp256k1.randomPrivateKey(), + }) + + const key = Key.from({ + expiry: 69420, + publicKey, + role: 'admin', + type: 'p256', + }) + + expect(key).toEqual({ + expiry: 69420, + publicKey, + role: 'admin', + type: 'p256', + }) + }) + + test('serialized', () => { + const publicKey = Secp256k1.getPublicKey({ + privateKey: Secp256k1.randomPrivateKey(), + }) + + const key = Key.from({ + expiry: 69420, + publicKey, + role: 'admin', + type: 'p256', + }) + const serialized = Key.serialize(key) + + expect(Key.from(serialized)).toEqual({ + expiry: 69420, + publicKey, + role: 'admin', + type: 'p256', + }) + }) +}) + +describe('fromP256', () => { + test('default', () => { + const key = Key.fromP256({ + privateKey: + '0x59ff6b8de3b3b39e94b6f9fc0590cf4e3eaa9b6736e6a49c9a6b324c4f58cb9f', + role: 'admin', + }) + + expect(key).toMatchInlineSnapshot(` + { + "expiry": 0, + "publicKey": { + "prefix": 4, + "x": 106772332543853129808885768556237579026047721040871197501406793325324706664735n, + "y": 110339676533900797749866890631856969312064778492080444630962038345769628880904n, + }, + "role": "admin", + "sign": [Function], + "type": "p256", + } + `) + }) + + test('args: expiry', () => { + const key = Key.fromP256({ + expiry: 69420, + privateKey: + '0x59ff6b8de3b3b39e94b6f9fc0590cf4e3eaa9b6736e6a49c9a6b324c4f58cb9f', + role: 'admin', + }) + + expect(key).toMatchInlineSnapshot(` + { + "expiry": 69420, + "publicKey": { + "prefix": 4, + "x": 106772332543853129808885768556237579026047721040871197501406793325324706664735n, + "y": 110339676533900797749866890631856969312064778492080444630962038345769628880904n, + }, + "role": "admin", + "sign": [Function], + "type": "p256", + } + `) + }) +}) + +describe('fromSecp256k1', () => { + test('default', () => { + const key = Key.fromSecp256k1({ + privateKey: + '0x59ff6b8de3b3b39e94b6f9fc0590cf4e3eaa9b6736e6a49c9a6b324c4f58cb9f', + role: 'admin', + }) + + expect(key).toMatchInlineSnapshot(` + { + "expiry": 0, + "publicKey": { + "prefix": 4, + "x": 44518355604327182364128173241945023694268305939358069173831053728054854486821n, + "y": 79963250654145194517329555417262110975421926937291144228957990645550809441590n, + }, + "role": "admin", + "sign": [Function], + "type": "secp256k1", + } + `) + }) +}) + +describe('fromWebAuthnP256', () => { + beforeAll(() => { + vi.stubGlobal('window', { + location: { + hostname: 'https://example.com', + }, + document: { + title: 'My Website', + }, + }) + }) + + afterAll(() => { + vi.restoreAllMocks() + }) + + test('default', async () => { + const credential = await WebAuthnP256.createCredential({ + createFn() { + return Promise.resolve({ + id: 'm1-bMPuAqpWhCxHZQZTT6e-lSPntQbh3opIoGe7g4Qs', + response: { + getPublicKey() { + return [ + 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, + 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 171, 137, 20, 0, 20, 15, 196, + 248, 233, 65, 206, 15, 249, 14, 65, 157, 233, 71, 10, 202, 202, + 97, 59, 189, 113, 122, 71, 117, 67, 80, 49, 167, 216, 132, 49, + 142, 145, 159, 211, 179, 229, 166, 49, 216, 102, 216, 163, 128, + 180, 64, 99, 231, 15, 12, 56, 30, 225, 110, 6, 82, 247, 249, + 117, 84, + ] + }, + }, + } as any) + }, + name: 'test', + }) + + const key = Key.fromWebAuthnP256({ + credential, + role: 'admin', + }) + + expect(key).toMatchInlineSnapshot(` + { + "expiry": 0, + "publicKey": { + "prefix": 4, + "x": 77587693192652859874025541476425832478302972220661277688017673393936226333095n, + "y": 97933141135755737384413290261786792525004108403409931527059712582886746584404n, + }, + "role": "admin", + "sign": [Function], + "type": "webauthn-p256", + } + `) + }) +}) + +describe('fromWebCryptoP256', () => { + test('default', async () => { + const keyPair = await WebCryptoP256.createKeyPair() + + const key = Key.fromWebCryptoP256({ + keyPair: { + privateKey: keyPair.privateKey, + publicKey: { + prefix: 4, + x: 29425393363637877844360099756708459701670665037779565927194637716883031208592n, + y: 4454192741171077737571435183656715320148197913661532282490480175757904146724n, + }, + }, + role: 'admin', + }) + + expect(key).toMatchInlineSnapshot(` + { + "expiry": 0, + "publicKey": { + "prefix": 4, + "x": 29425393363637877844360099756708459701670665037779565927194637716883031208592n, + "y": 4454192741171077737571435183656715320148197913661532282490480175757904146724n, + }, + "role": "admin", + "sign": [Function], + "type": "p256", + } + `) + }) +}) + +describe('serialize', () => { + test('default', () => { + const key = Key.fromP256({ + privateKey: + '0x59ff6b8de3b3b39e94b6f9fc0590cf4e3eaa9b6736e6a49c9a6b324c4f58cb9f', + role: 'admin', + }) + + expect(Key.serialize(key)).toMatchInlineSnapshot(` + { + "expiry": 0, + "isSuperAdmin": true, + "keyType": 0, + "publicKey": "0x04ec0effa5f2f378cbf7fd2fa7ca1e8dc51cf777c129fa1c00a0e9a9205f2e511ff3f20b34a4e0b50587d055c0e0fad33d32cf1147d3bb2538fbab0d15d8e65008", + } + `) + }) +}) diff --git a/src/core/internal/key.ts b/src/core/internal/key.ts new file mode 100644 index 00000000..cf4c53d4 --- /dev/null +++ b/src/core/internal/key.ts @@ -0,0 +1,592 @@ +import type * as Bytes from 'ox/Bytes' +import type * as Hex from 'ox/Hex' +import * as P256 from 'ox/P256' +import * as PublicKey from 'ox/PublicKey' +import * as Secp256k1 from 'ox/Secp256k1' +import type * as Signature from 'ox/Signature' +import * as WebAuthnP256 from 'ox/WebAuthnP256' +import * as WebCryptoP256 from 'ox/WebCryptoP256' + +export type Parameters = { + role: 'owner' | 'admin' | 'session' + type: 'p256' | 'secp256k1' | 'webauthn-p256' +} + +/** Key on a delegated account. */ +export type Key = { + expiry: number + publicKey: PublicKey.PublicKey + sign?: (parameters: { payload: Hex.Hex }) => + | Promise< + Signature.Signature & { + metadata?: + | (WebAuthnP256.SignMetadata & { prehash?: boolean | undefined }) + | undefined + } + > + | undefined + role: parameters['role'] + type: parameters['type'] +} + +/** Serialized (contract-compatible) format of a key. */ +export type Serialized = { + expiry: number + isSuperAdmin: boolean + keyType: number + publicKey: Hex.Hex +} + +/** Key type to serialized key type mapping. */ +const toSerializedKeyType = { + p256: 0, + 'webauthn-p256': 1, + secp256k1: 2, +} as const + +/** Serialized key type to key type mapping. */ +const fromSerializedKeyType = { + 0: 'p256', + 1: 'webauthn-p256', + 2: 'secp256k1', +} as const + +/** + * Creates a random P256 key. + * + * @example + * ```ts + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.createP256({ + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.createP256({ + * expiry: 1714857600, + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns P256 key. + */ +export function createP256( + parameters: createP256.Parameters, +): Key<{ + role: role + type: 'p256' +}> { + const privateKey = P256.randomPrivateKey() + return fromP256({ + ...parameters, + privateKey, + }) +} + +export declare namespace createP256 { + type Parameters = { + /** Expiry. */ + expiry?: fromP256.Parameters['expiry'] + /** Role. */ + role: fromP256.Parameters['role'] + } +} + +/** + * Creates a random Secp256k1 key. + * + * @example + * ```ts + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.createSecp256k1({ + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.createSecp256k1({ + * expiry: 1714857600, + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns Secp256k1 key. + */ +export function createSecp256k1( + parameters: createSecp256k1.Parameters, +): Key<{ + role: role + type: 'secp256k1' +}> { + const privateKey = Secp256k1.randomPrivateKey() + return fromSecp256k1({ + ...parameters, + privateKey, + }) +} + +export declare namespace createSecp256k1 { + type Parameters = { + /** Expiry. */ + expiry?: fromSecp256k1.Parameters['expiry'] + /** Role. */ + role: fromSecp256k1.Parameters['role'] + } +} + +/** + * Creates a WebAuthnP256 key. + * + * @example + * ```ts + * import { Bytes } from 'ox' + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.createWebAuthnP256({ + * label: 'My Key', + * role: 'admin', + * userId: Bytes.from('0x0000000000000000000000000000000000000000'), + * }) + * + * // Session Key + * const key = Key.createWebAuthnP256({ + * expiry: 1714857600, + * label: 'My Key', + * role: 'session', + * userId: Bytes.from('0x0000000000000000000000000000000000000000'), + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns WebAuthnP256 key. + */ +export async function createWebAuthnP256< + const role extends 'admin' | 'session', +>( + parameters: createWebAuthnP256.Parameters, +): Promise< + Key<{ + role: role + type: 'webauthn-p256' + }> +> { + const { createFn, label, rpId, userId } = parameters + + const credential = await WebAuthnP256.createCredential({ + authenticatorSelection: { + requireResidentKey: false, + residentKey: 'preferred', + userVerification: 'required', + }, + createFn, + rp: rpId + ? { + id: rpId, + name: rpId, + } + : undefined, + user: { + displayName: label, + name: label, + id: userId, + }, + }) + + return fromWebAuthnP256({ + ...parameters, + credential, + }) +} + +export declare namespace createWebAuthnP256 { + type Parameters = { + /** + * Credential creation function. Useful for environments that do not support + * the WebAuthn API natively (i.e. React Native or testing environments). + * + * @default window.navigator.credentials.create + */ + createFn?: WebAuthnP256.createCredential.Options['createFn'] | undefined + /** Expiry. */ + expiry?: fromWebAuthnP256.Parameters['expiry'] + /** Label. */ + label: string + /** Role. */ + role: fromWebAuthnP256.Parameters['role'] + /** Relying Party ID. */ + rpId?: string | undefined + /** User ID. */ + userId: Bytes.Bytes + } +} + +/** + * Creates a random WebCryptoP256 key. + * + * @example + * ```ts + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.createWebCryptoP256({ + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.createWebCryptoP256({ + * expiry: 1714857600, + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns WebCryptoP256 key. + */ +export async function createWebCryptoP256< + const role extends 'admin' | 'session', +>( + parameters: createWebCryptoP256.Parameters, +): Promise< + Key<{ + role: role + type: 'p256' + }> +> { + const keyPair = await WebCryptoP256.createKeyPair() + return fromWebCryptoP256({ + ...parameters, + keyPair, + }) +} + +export declare namespace createWebCryptoP256 { + type Parameters = { + /** Expiry. */ + expiry?: fromP256.Parameters['expiry'] + /** Role. */ + role: fromP256.Parameters['role'] + } +} + +/** + * Deserializes a key from its serialized format. + * + * @example + * ```ts + * import * as Key from './key.js' + * + * const key = Key.deserialize({ + * expiry: 0, + * isSuperAdmin: false, + * keyType: 0, + * publicKey: '0x04ec0effa5f2f378cbf7fd2fa7ca1e8dc51cf777c129fa1c00a0e9a9205f2e511ff3f20b34a4e0b50587d055c0e0fad33d32cf1147d3bb2538fbab0d15d8e65008', + * }) + * ``` + * + * @param serialized - Serialized key. + * @returns Key. + */ +export function deserialize(serialized: Serialized): Key { + return { + expiry: serialized.expiry, + publicKey: PublicKey.fromHex(serialized.publicKey), + role: serialized.isSuperAdmin ? 'admin' : 'session', + type: (fromSerializedKeyType as any)[serialized.keyType], + } +} + +/** + * Instantiates a key from its parameters. + * + * @example + * ```ts + * import { P256 } from 'ox' + * import * as Key from './key.js' + * + * const privateKey = P256.randomPrivateKey() + * const publicKey = P256.getPublicKey({ privateKey }) + * + * const key = Key.from({ + * expiry: 0, + * publicKey, + * role: 'admin', + * async sign({ payload }) { + * return P256.sign({ payload, privateKey }) + * }, + * type: 'p256', + * }) + * ``` + * + * @param key - Key. + * @returns Key. + */ +export function from( + key: key | Key | Serialized, +): key extends Key ? key : Key { + if ('isSuperAdmin' in key) return deserialize(key) as never + + const { expiry = 0, publicKey, role, sign, type } = key + return { expiry, publicKey, role, sign, type } as never +} + +/** + * Instantiates a P256 key from its parameters. + * + * @example + * ```ts + * import { P256 } from 'ox' + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.fromP256({ + * privateKey: P256.randomPrivateKey(), + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.fromP256({ + * expiry: 1714857600, + * privateKey: P256.randomPrivateKey(), + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns P256 key. + */ +export function fromP256( + parameters: fromP256.Parameters, +): Key<{ + role: role + type: 'p256' +}> { + const { privateKey } = parameters + const publicKey = P256.getPublicKey({ privateKey }) + return from({ + ...(parameters as any), + publicKey, + async sign({ payload }) { + return P256.sign({ payload, privateKey }) + }, + type: 'p256', + }) +} + +export declare namespace fromP256 { + type Parameters = { + /** Expiry. */ + expiry?: Key['expiry'] | undefined + /** P256 private key. */ + privateKey: Hex.Hex + /** Role. */ + role: role | 'admin' | 'session' + } +} + +/** + * Instantiates a Secp256k1 key from its parameters. + * + * @example + * ```ts + * import { Secp256k1 } from 'ox' + * import * as Key from './key.js' + * + * // Admin Key + * const key = Key.fromSecp256k1({ + * privateKey: Secp256k1.randomPrivateKey(), + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.fromSecp256k1({ + * expiry: 1714857600, + * privateKey: Secp256k1.randomPrivateKey(), + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns Secp256k1 key. + */ +export function fromSecp256k1( + parameters: fromSecp256k1.Parameters, +): Key<{ + role: role + type: 'secp256k1' +}> { + const { privateKey } = parameters + const publicKey = Secp256k1.getPublicKey({ privateKey }) + return from({ + ...(parameters as any), + publicKey, + async sign({ payload }) { + return Secp256k1.sign({ payload, privateKey }) + }, + type: 'secp256k1', + }) +} + +export declare namespace fromSecp256k1 { + type Parameters = { + /** Expiry. */ + expiry?: Key['expiry'] | undefined + /** Secp256k1 private key. */ + privateKey: Hex.Hex + /** Role. */ + role: role | 'admin' | 'session' + } +} + +/** + * Instantiates a WebAuthnP256 key from its parameters. + * + * @example + * ```ts + * import { WebAuthnP256 } from 'ox' + * import * as Key from './key.js' + * + * const credential = await WebAuthnP256.createCredential({ name: 'My Key' }) + * + * // Admin Key + * const key = Key.fromWebAuthnP256({ + * credential, + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.fromWebAuthnP256({ + * expiry: 1714857600, + * credential, + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns WebAuthnP256 key. + */ +export function fromWebAuthnP256( + parameters: fromWebAuthnP256.Parameters, +): Key<{ + role: role + type: 'webauthn-p256' +}> { + const { credential, rpId } = parameters + + return from({ + ...(parameters as any), + publicKey: credential.publicKey, + async sign({ payload }) { + return WebAuthnP256.sign({ + challenge: payload, + credentialId: credential.id, + rpId, + }) + }, + type: 'webauthn-p256', + }) +} + +export declare namespace fromWebAuthnP256 { + type Parameters = { + /** Expiry. */ + expiry?: Key['expiry'] | undefined + /** WebAuthnP256 Credential. */ + credential: WebAuthnP256.P256Credential + /** Role. */ + role: role | 'admin' | 'session' + /** Relying Party ID. */ + rpId?: string | undefined + } +} + +/** + * Instantiates a WebCryptoP256 key from its parameters. + * + * @example + * ```ts + * import { WebCryptoP256 } from 'ox' + * import * as Key from './key.js' + * + * const keyPair = await WebCryptoP256.createKeyPair() + * + * // Admin Key + * const key = Key.fromWebCryptoP256({ + * keyPair, + * role: 'admin', + * }) + * + * // Session Key + * const key = Key.fromWebCryptoP256({ + * expiry: 1714857600, + * keyPair, + * role: 'session', + * }) + * ``` + * + * @param parameters - Key parameters. + * @returns WebCryptoP256 key. + */ +export function fromWebCryptoP256( + parameters: fromWebCryptoP256.Parameters, +): Key<{ role: role; type: 'p256' }> { + const { keyPair } = parameters + const { publicKey, privateKey } = keyPair + return from({ + ...(parameters as any), + publicKey, + async sign({ payload }) { + const signature = await WebCryptoP256.sign({ payload, privateKey }) + return { + ...signature, + metadata: { + prehash: true, + }, + } + }, + type: 'p256', + }) +} + +export declare namespace fromWebCryptoP256 { + type Parameters = { + /** Expiry. */ + expiry?: Key['expiry'] | undefined + /** P256 private key. */ + keyPair: Awaited> + /** Role. */ + role: role | 'admin' | 'session' + } +} + +/** + * Serializes a key to a contract-compatible format. + * + * @example + * ```ts + * import * as Key from './key.js' + * + * const key = Key.createP256({ + * role: 'admin', + * }) + * + * const serialized = Key.serialize(key) + * ``` + * + * @param key - Key. + * @returns Serialized key. + */ +export function serialize(key: Key): Serialized { + const { expiry = 0, publicKey, role, type } = key + return { + expiry, + isSuperAdmin: role === 'owner' || role === 'admin', + keyType: toSerializedKeyType[type], + publicKey: PublicKey.toHex(publicKey), + } +} diff --git a/src/core/internal/provider.test.ts b/src/core/internal/provider.test.ts new file mode 100644 index 00000000..2e8eef2e --- /dev/null +++ b/src/core/internal/provider.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from 'vitest' + +import { anvil, porto } from '../../../test/src/config.js' + +test('default', async () => { + const code = await porto.provider.request({ + method: 'eth_getCode', + params: [anvil.contracts.accountDelegation.address, 'latest'], + }) + expect(code).toMatchSnapshot() +}) diff --git a/src/package.json b/src/package.json index 1148454a..2785c8c1 100644 --- a/src/package.json +++ b/src/package.json @@ -24,7 +24,7 @@ "@tanstack/react-query": ">=5.59.0", "react": ">=18", "typescript": ">=5.4.0", - "viem": ">=2.21.51", + "viem": ">=2.21.60", "wagmi": ">=2.0.0" }, "peerDependenciesMeta": { diff --git a/test/src/anvil.json b/test/src/anvil.json new file mode 100644 index 00000000..66d650a7 --- /dev/null +++ b/test/src/anvil.json @@ -0,0 +1,117 @@ +{ + "block": { + "number": "0x0", + "coinbase": "0x0000000000000000000000000000000000000000", + "timestamp": "0x1", + "gas_limit": "0x1c9c380", + "basefee": "0x3b9aca00", + "difficulty": "0x0", + "prevrandao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blob_excess_gas_and_price": { "excess_blob_gas": 0, "blob_gasprice": 1 } + }, + "accounts": { + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65": { + "nonce": 12, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": { + "nonce": 10, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": { + "nonce": 45, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x4e59b44847b379578588920ca78fbf26c0b4956c": { + "nonce": 3731, + "balance": "0x0", + "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3", + "storage": {} + }, + "0x70997970c51812dc3a010c7d01b50e0d17dc79c8": { + "nonce": 112, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x90f79bf6eb2c4f870365e785982e1f101e93b906": { + "nonce": 40, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x976ea74026e726554db657fa54763abd0c3a0aa9": { + "nonce": 12, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc": { + "nonce": 30, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720": { + "nonce": 9, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { + "nonce": 663, + "balance": "0x21e19e0c9bab2400000", + "code": "0x", + "storage": {} + }, + "0x0ff027b63351364071425cf65d4fece75a8e17b8": { + "nonce": 0, + "balance": "0x21e19e0c9bab2400000", + "code": "0x6080604052600436106101c5575f3560e01c806384b0196e116100f6578063bf53096911610094578063e9ae5c5311610063578063e9ae5c53146105f9578063f0c60f1a1461060c578063fac750e014610620578063ff619c6b14610634576101cc565b8063bf5309691461054e578063cb4774c41461056d578063cebfe3361461058e578063d03c7914146105ad576101cc565b8063a2e2f930116100d0578063a2e2f930146104d2578063a840fe49146104f1578063b70e36f014610510578063b75c7dc61461052f576101cc565b806384b0196e1461045957806394430fa5146104805780639c42fb59146104a3576101cc565b80632f3f30c711610163578063515c9d6d1161013d578063515c9d6d146103cb57806360d2f33d146103eb5780636ae269cc1461041e5780636fd914541461043a576101cc565b80632f3f30c71461037857806335058501146103925780634223b5c2146103ac576101cc565b8063136a12f71161019f578063136a12f7146102ab5780631626ba7e146102cc5780631a912f3e1461030457806320606b7014610345576101cc565b80630cef73b41461020557806311a86fd61461024057806312aaac701461027f576101cc565b366101cc57005b5f3560e01c63bc197c81811463f23a6e6182141763150b7a02821417156101f757806020526020603cf35b50633c10b94e5f526004601cfd5b348015610210575f80fd5b5061022461021f366004612068565b610653565b6040805192151583526020830191909152015b60405180910390f35b34801561024b575f80fd5b5061026773323232323232323232323232323232323232323281565b6040516001600160a01b039091168152602001610237565b34801561028a575f80fd5b5061029e6102993660046120b0565b61066d565b6040516102379190612109565b3480156102b6575f80fd5b506102ca6102c536600461218b565b61075d565b005b3480156102d7575f80fd5b506102eb6102e6366004612068565b610868565b6040516001600160e01b03199091168152602001610237565b34801561030f575f80fd5b506103377f84fa2cf05cd88e992eae77e851af68a4ee278dcff6ef504e487a55b3baadfbe581565b604051908152602001610237565b348015610350575f80fd5b506103377f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b348015610383575f80fd5b506102eb630707070760e51b81565b34801561039d575f80fd5b506102eb631919191960e11b81565b3480156103b7575f80fd5b5061029e6103c63660046120b0565b61089b565b3480156103d6575f80fd5b506103375f8051602061266f83398151915281565b3480156103f6575f80fd5b506103377fe530e62dece51c9bec26701907051ddc8420a62f028096eeb58263193e84e04981565b348015610429575f80fd5b50686d3d4e7fb92a52381554610337565b348015610445575f80fd5b506103376104543660046121e5565b6108d9565b348015610464575f80fd5b5061046d610a2c565b604051610237979695949392919061225a565b34801561048b575f80fd5b506102676fac830f1181f6aab6862e71edc248941c81565b3480156104ae575f80fd5b506104c26104bd3660046122f0565b610a8d565b6040519015158152602001610237565b3480156104dd575f80fd5b506104c26104ec3660046120b0565b610ad1565b3480156104fc575f80fd5b5061033761050b3660046123e2565b610af9565b34801561051b575f80fd5b506102ca61052a3660046120b0565b610b32565b34801561053a575f80fd5b506102ca6105493660046120b0565b610b5d565b348015610559575f80fd5b506102ca610568366004612491565b610bb2565b348015610578575f80fd5b50610581610c56565b60405161023791906124d0565b348015610599575f80fd5b506103376105a83660046123e2565b610c6f565b3480156105b8575f80fd5b506104c26105c73660046120b0565b690100000000007821000160b09190911c69ffff00000000ffffffff1690811460011b600160481b9190911417151590565b6102ca610607366004612068565b610cd7565b348015610617575f80fd5b50610337610d60565b34801561062b575f80fd5b50610337610df3565b34801561063f575f80fd5b506104c261064e3660046124e2565b610e06565b5f806106618585855f611099565b91509150935093915050565b604080516080810182525f80825260208201819052918101919091526060808201525f828152686d3d4e7fb92a523817602052604081206106ad906112bb565b905080515f036106d05760405163395ed8c160e21b815260040160405180910390fd5b8051600619015f6106e48383016020015190565b60d881901c855260c881901c915060d01c60ff166002811115610709576107096120c7565b8460200190600281111561071f5761071f6120c7565b90816002811115610732576107326120c7565b90525060ff81161515604085015261074f83838151811082025290565b606085015250919392505050565b33301461077c576040516282b42960e81b815260040160405180910390fd5b8361079a57604051638707510560e01b815260040160405180910390fd5b6107a48383611321565b156107cf576107b28461134b565b6107cf576040516303a6f8c760e21b815260040160405180910390fd5b5f82815260188490526004859052603881208152683c149ebf7b8e6c5e226020818152604092839020805485151560ff19909116811790915583518881526001600160a01b038816928101929092526001600160e01b03198616828501526060820152915190917f7eb91b8ac56c0864a4e4f5598082d140d04bed1a4dd62a41d605be2430c494e1919081900360800190a15050505050565b5f806108778585856001611099565b509050806108895763ffffffff61088f565b631626ba7e5b60e01b95945050505050565b604080516080810182525f80825260208201819052918101919091526060808201526108d3610299686d3d4e7fb92a5238168461135f565b92915050565b5f806108f58460408051828152600190920160051b8201905290565b90505f5b848110156109b857368686838181106109145761091461253a565b9050602002810190610926919061254e565b90506109ae8261099f7f84fa2cf05cd88e992eae77e851af68a4ee278dcff6ef504e487a55b3baadfbe561095d602086018661256c565b6001600160a01b0316602086013561098061097b6040890189612587565b6113a8565b6040805194855260208501939093529183015260608201526080902090565b600190910160051b8501528390565b50506001016108f9565b50610a23610a1e7fe530e62dece51c9bec26701907051ddc8420a62f028096eeb58263193e84e0496109f284805160051b60209091012090565b686d3d4e7fb92a5238155460408051938452602084019290925290820187905260608201526080902090565b6113b9565b95945050505050565b600f60f81b6060805f808083610a7b604080518082018252600a8152692232b632b3b0ba34b7b760b11b60208083019190915282518084019093526005835264302e302e3160d81b9083015291565b97989097965046955030945091925090565b5f336fac830f1181f6aab6862e71edc248941c14610abd576040516282b42960e81b815260040160405180910390fd5b610ac88333846114cf565b50600192915050565b600881901c5f908152686d3d4e7fb92a523814602052604081205460ff83161c6001166108d3565b5f6108d382602001516002811115610b1357610b136120c7565b60ff168360600151805190602001205f1c5f9182526020526040902090565b333014610b51576040516282b42960e81b815260040160405180910390fd5b610b5a816114f7565b50565b333014610b7c576040516282b42960e81b815260040160405180910390fd5b610b8581611553565b60405181907fe5af7daed5ab2a2dc5f98d53619f05089c0c14d11a6621f6b906a2366c9a7ab3905f90a250565b333014610bd1576040516282b42960e81b815260040160405180910390fd5b610c1982828080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610c1392506112ae915050565b906115a7565b7faec6ef4baadc9acbdf52442522dfffda03abe29adba8d4af611bcef4cbe0c9ad8282604051610c4a9291906125ca565b60405180910390a15050565b6060610c6a686d3d4e7fb92a5238136112bb565b905090565b5f333014610c8f576040516282b42960e81b815260040160405180910390fd5b610c98826115ff565b9050807f3d3a48be5a98628ecf98a6201185102da78bbab8f63a4b2d6b9eef354f5131f583604051610cca9190612109565b60405180910390a2919050565b690100000000007821000160b084901c69ffff00000000ffffffff1690811460011b600160481b9190911417365f818184610d1957637f1812755f526004601cfd5b5085358087016020810194503592505f90604011600286141115610d47575050602080860135860190810190355b610d5688888887878787611674565b5050505050505050565b5f333014610d80576040516282b42960e81b815260040160405180910390fd5b50686d3d4e7fb92a523815805460408051828152426020808301919091523382840152606090912063ffffffff169092019283905580518381529051686d3d4e7fb92a523813927f7328006ebae4716b8db9514af69091e0ad74bec61dfdc256ed5446b234aa5424928290030190a15090565b5f610c6a686d3d4e7fb92a52381661178b565b5f84610e1457506001611091565b683c149ebf7b8e6c5e22631919191960e11b60048410610e32575083355b83610e415750630707070760e51b5b610e4b8682611321565b15610e6757610e598761134b565b610e67575f92505050611091565b5f818152601887905260048890526038812081526020839052604090205460ff1615610e9857600192505050611091565b5f81815273323232323232323232323232323232323232323260185260048890526038812081526020839052604090205460ff1615610edc57600192505050611091565b5f81815260188790525f8051602061266f8339815191526004526038812081526020839052604090205460ff1615610f1957600192505050611091565b5f8181527332323232323232323232323232323232323232326018525f8051602061266f8339815191526004526038812081526020839052604090205460ff1615610f6957600192505050611091565b631919191960e11b5f908152601887905260048890526038812081526020839052604090205460ff1615610fa257600192505050611091565b631919191960e11b5f90815273323232323232323232323232323232323232323260185260048890526038812081526020839052604090205460ff1615610fee57600192505050611091565b631919191960e11b5f90815260188790525f8051602061266f8339815191526004526038812081526020839052604090205460ff161561103357600192505050611091565b631919191960e11b5f9081527332323232323232323232323232323232323232326018525f8051602061266f8339815191526004526038812081526020839052604090205460ff161561108b57600192505050611091565b5f925050505b949350505050565b5f80604184146040851417156110c957306110b58787876117d7565b6001600160a01b03161491505f90506112a5565b60218410156110dc57505f9050806112a5565b506020198381018481118186180281189486019182013591601f19013560ff161561110d5761110a8761185f565b96505b505f6111188261066d565b6040810151909150158415151615611133575f9250506112a5565b805164ffffffffff164281109015151615611151575f9250506112a5565b5f81602001516002811115611168576111686120c7565b036111c3575f80603f8711883581029060208a013502915091505f806111a7856060015180516020820151604090920151603f90911191820292910290565b915091506111b88b8585858561187d565b9650505050506112a3565b6001816020015160028111156111db576111db6120c7565b0361126057606081810151805160208083015160409384015184518084018e9052855180820385018152601f8d018590049094028101870186529485018b8152603f9490941091820295910293611257935f92611250928e918e918291018382808284375f9201919091525061190f92505050565b85856119f3565b945050506112a3565b600281602001516002811115611278576112786120c7565b036112a3576112a0816060015180602001905181019061129891906125f8565b888888611b12565b92505b505b94509492505050565b686d3d4e7fb92a52381390565b60405181546020820190600881901c5f8260ff8417146112e957505080825260ff8116601f8082111561130b575b855f5260205f205b8160051c810154828601526020820191508282106112f157505b508084525f920191825250602001604052919050565b5f63e9ae5c5360e01b6001600160e01b0319831614306001600160a01b03851614165b9392505050565b5f6113558261066d565b6040015192915050565b6318fb58646004525f8281526024902081015468fbb67fda52d4bfb8bf811415026113898361178b565b82106108d357604051634e23d03560e01b815260040160405180910390fd5b5f8183604051375060405120919050565b7f06012d2aedbb397c1914278c3206cec06702f79ceb18361e1ddb2fcc068c324f7f0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa330147f0000000000000000000000000000000000000000000000000000000000007a694614166114ac5750604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527f6c157b110f3bc0280dba8ae624dab3ba623d9bab8692057c96d59c9188d52cb260208201527fae209a0b48f21c054280f2455d32cf309387644879d9acbd8ffc1991638118859181019190915246606082015230608082015260a090205b6719010000000000005f5280601a5281603a52604260182090505f603a52919050565b6001600160a01b0383166114ec576114e78282611be0565b505050565b6114e7838383611bf9565b600881901c5f908152686d3d4e7fb92a523814602052604090208054600160ff84161b1790556040518181527f4d9dbebf1d909894d9c26fe228c27cec643b2cb490124e5b658f4edd203c20c19060200160405180910390a150565b5f818152686d3d4e7fb92a5238176020526040812055686d3d4e7fb92a523813611586686d3d4e7fb92a52381683611c43565b6115a35760405163395ed8c160e21b815260040160405180910390fd5b5050565b80518060081b60ff175f60fe83116115d0575050601f8281015160081b821790808311156115f7575b60208401855f5260205f205b828201518360051c8201556020830192508483106115dc5750505b509092555050565b5f61160982610af9565b90505f686d3d4e7fb92a5238136060840151845160208087015160408089015190519596506116609561163e95949301612613565b60408051601f198184030181529181525f8581526004850160205220906115a7565b61166d6003820183611d4f565b5050919050565b6fac830f1181f6aab6862e71edc248941b1933016116cc5760408110156116ae576040516355fe73fd60e11b815260040160405180910390fd5b6116b88235611e6a565b6116c784846020850135611e91565b611782565b806116fb573330146116f0576040516282b42960e81b815260040160405180910390fd5b6116c784845f611e91565b602081101561171d576040516355fe73fd60e11b815260040160405180910390fd5b813561172881611e6a565b5f806117526117388888866108d9565b602080871081881802188088019080880390881102610653565b9150915081611773576040516282b42960e81b815260040160405180910390fd5b61177e878783611e91565b5050505b50505050505050565b6318fb58646004525f818152602481208019548060011c92508061166d5781545f93501561166d5760019250828201541561166d5760029250828201541561166d575060039392505050565b5f60405182604081146117f25760418114611819575061184a565b60208581013560ff81901c601b0190915285356040526001600160ff1b031660605261182a565b60408501355f1a6020526040856040375b50845f526020600160805f60015afa5191505f606052806040523d611857575b638baa579f5f526004601cfd5b509392505050565b5f815f526020600160205f60025afa5190503d61187857fe5b919050565b5f6040518681528560208201528460408201528360608201528260808201525f805260205f60a0836101005afa503d6118da5760203d60a0836dcb83347beb24c695bbb85dbe99b75afa503d6118da5763d0d5039b3d526004601cfd5b505f516001147f7fffffff800000007fffffffffffffffde737d56d38bcf4279dce5617e3192a8851110905095945050505050565b6040805160c0810182526060808252602082018190525f92820183905281018290526080810182905260a0810191909152815160c081106119ed5760208301818101818251018281108260c0830111171561196c575050506119ed565b808151019250806020820151018181108382111782851084861117171561199657505050506119ed565b82815160208301011183855160208701011117156119b757505050506119ed565b8386528060208701525060408101516040860152606081015160608601526080810151608086015260a081015160a08601525050505b50919050565b5f805f611a0288600180611edf565b905060208601518051602082019150604088015160608901518451600d81016c1131b430b63632b733b2911d1160991b60981c8752848482011060228286890101515f1a14168160138901208286890120141685846014011085851760801c1074113a3cb832911d113bb2b130baba34371733b2ba1160591b60581c8589015160581c14161698505080865250505087515189151560021b600117808160218c5101511614602083118816169650508515611ae657602089510181810180516020600160208601856020868a8c60025afa60011b5afa51915295503d9050611ae657fe5b5050508215611b0757611b048287608001518860a00151888861187d565b92505b505095945050505050565b5f6001600160a01b03851615611091576040518260408114611b3c5760418114611b635750611b98565b60208581013560ff81901c601b0190915285356040526001600160ff1b0316606052611b74565b60408501355f1a6020526040856040375b50845f526020600160805f60015afa5180871860601b3d119250505f606052806040525b81611bd757631626ba7e60e01b80825285600483015260248201604081528460448401528486606485013760208160648701858b5afa90519091141691505b50949350505050565b5f385f3884865af16115a35763b12d13eb5f526004601cfd5b816014528060345263a9059cbb60601b5f5260205f604460105f875af18060015f511416611c3957803d853b151710611c39576390b8ec185f526004601cfd5b505f603452505050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf8303611c705763f5a267f15f526004601cfd5b82611c825768fbb67fda52d4bfb8bf92505b80195480611ceb576001925083825403611caf5760018201805483556002830180549091555f9055611d47565b83600183015403611ccd5760028201805460018401555f9055611d47565b83600283015403611ce3575f6002830155611d47565b5f9250611d47565b81602052835f5260405f20805480611d04575050611d47565b60018360011c039250826001820314611d33578284015480600183038601555f84860155805f52508060405f20555b5060018260011b178319555f815550600192505b505092915050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf8303611d7c5763f5a267f15f526004601cfd5b82611d8e5768fbb67fda52d4bfb8bf92505b8019548160205280611e3257815480611dae578483556001935050611d47565b848103611dbb5750611d47565b600183015480611dd657856001850155600194505050611d47565b858103611de4575050611d47565b600284015480611e005786600286015560019550505050611d47565b868103611e0f57505050611d47565b5f9283526040808420600190559183528183206002905582529020600390555060075b835f5260405f208054611e6157600191821c8381018690558083019182905590821b8217831955909250611d47565b50505092915050565b611e7381610ad1565b15610b5157604051633ab3447f60e11b815260040160405180910390fd5b600582901b5f5b818114611ed8576020818101918601358601803580153002179181810135916040810135019081019035611ecf848484848b611fd0565b50505050611e98565b5050505050565b606083518015611857576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f526020830181810183886020010180515f82525b60038a0199508951603f8160121c16515f53603f81600c1c1651600153603f8160061c1651600253603f811651600353505f518452600484019350828410611f5a579052602001604052613d3d60f01b60038406600204808303919091525f861515909102918290035290038252509392505050565b611fdc81868585610e06565b611ff8576040516282b42960e81b815260040160405180910390fd5b611ed88585858585604051828482375f388483888a5af161201b573d5f823e3d81fd5b505050505050565b5f8083601f840112612033575f80fd5b50813567ffffffffffffffff81111561204a575f80fd5b602083019150836020828501011115612061575f80fd5b9250929050565b5f805f6040848603121561207a575f80fd5b83359250602084013567ffffffffffffffff811115612097575f80fd5b6120a386828701612023565b9497909650939450505050565b5f602082840312156120c0575f80fd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6020815264ffffffffff82511660208201525f60208301516003811061213d57634e487b7160e01b5f52602160045260245ffd5b80604084015250604083015115156060830152606083015160808084015261109160a08401826120db565b6001600160a01b0381168114610b5a575f80fd5b80358015158114611878575f80fd5b5f805f806080858703121561219e575f80fd5b8435935060208501356121b081612168565b925060408501356001600160e01b0319811681146121cc575f80fd5b91506121da6060860161217c565b905092959194509250565b5f805f604084860312156121f7575f80fd5b833567ffffffffffffffff81111561220d575f80fd5b8401601f8101861361221d575f80fd5b803567ffffffffffffffff811115612233575f80fd5b8660208260051b8401011115612247575f80fd5b6020918201979096509401359392505050565b60ff60f81b8816815260e060208201525f61227860e08301896120db565b828103604084015261228a81896120db565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b818110156122df5783518352602093840193909201916001016122c1565b50909b9a5050505050505050505050565b5f8060408385031215612301575f80fd5b823561230c81612168565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff811182821017156123515761235161231a565b60405290565b5f82601f830112612366575f80fd5b813567ffffffffffffffff8111156123805761238061231a565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123af576123af61231a565b6040528181528382016020018510156123c6575f80fd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156123f2575f80fd5b813567ffffffffffffffff811115612408575f80fd5b820160808185031215612419575f80fd5b61242161232e565b813564ffffffffff81168114612435575f80fd5b8152602082013560038110612448575f80fd5b60208201526124596040830161217c565b6040820152606082013567ffffffffffffffff811115612477575f80fd5b61248386828501612357565b606083015250949350505050565b5f80602083850312156124a2575f80fd5b823567ffffffffffffffff8111156124b8575f80fd5b6124c485828601612023565b90969095509350505050565b602081525f61134460208301846120db565b5f805f80606085870312156124f5575f80fd5b84359350602085013561250781612168565b9250604085013567ffffffffffffffff811115612522575f80fd5b61252e87828801612023565b95989497509550505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112612562575f80fd5b9190910192915050565b5f6020828403121561257c575f80fd5b813561134481612168565b5f808335601e1984360301811261259c575f80fd5b83018035915067ffffffffffffffff8211156125b6575f80fd5b602001915036819003821315612061575f80fd5b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f60208284031215612608575f80fd5b815161134481612168565b5f85518060208801845e60d886901b6001600160d81b0319169083019081526003851061264e57634e487b7160e01b5f52602160045260245ffd5b60f894851b600582015292151590931b600683015250600701939250505056fe3232323232323232323232323232323232323232323232323232323232323232a2646970667358221220fedfc3184b2b333b20591e8e82d687d62f41e28fa92d349d78b640fb4d41df5764736f6c634300081a0033", + "storage": {} + } + }, + "best_block_number": "0x12f2974", + "blocks": [ + { + "header": { + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x0000000000000000000000000000000000000000", + "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x0", + "gasLimit": "0x1c9c380", + "gasUsed": "0x0", + "timestamp": "0x67749feb", + "extraData": "0x", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x3b9aca00", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [], + "ommers": [] + } + ], + "transactions": [], + "historical_states": null +} diff --git a/test/src/anvil.ts b/test/src/anvil.ts index 1f1d2c5c..8b8c7335 100644 --- a/test/src/anvil.ts +++ b/test/src/anvil.ts @@ -1,12 +1,21 @@ -import { RpcTransport } from 'ox' +import { resolve } from 'node:path' +import { Provider, RpcTransport } from 'ox' import { createServer } from 'prool' import { type AnvilParameters, anvil } from 'prool/instances' +import { + http, + type TransactionRequest, + createClient, + formatTransaction, +} from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { prepareTransactionRequest, signTransaction } from 'viem/actions' export const anvilMainnet = defineAnvil({ - forkUrl: getEnv('VITE_ANVIL_FORK_URL', 'https://1.rpc.thirdweb.com'), + forkUrl: getEnv('VITE_ANVIL_FORK_URL', 'https://eth.merkle.io'), forkBlockNumber: 19868020n, - // noMining: true, port: 8545, + loadState: resolve(import.meta.dirname, 'anvil.json'), }) ///////////////////////////////////////////////////////////////// @@ -33,11 +42,39 @@ function defineAnvil(parameters: AnvilParameters) { hardfork: 'Prague', } as const + const client = createClient({ + transport: http(rpcUrl), + }) + const transport = RpcTransport.fromHttp(rpcUrl) + const provider = Provider.from({ + async request(args) { + if (args.method === 'eth_sendTransaction') { + const transaction = formatTransaction( + (args.params as any)[0], + ) as TransactionRequest + + const request = await prepareTransactionRequest(client, { + ...transaction, + account: privateKeyToAccount( + '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80', + ), + chain: null, + }) + + const serialized = await signTransaction(client, request) + + args.method = 'eth_sendRawTransaction' as any + args.params = [serialized] as any + } + + return transport.request(args as any) + }, + }) return { config, - request: transport.request, + request: provider.request, async restart() { await fetch(`${rpcUrl}/restart`) }, diff --git a/test/src/config.ts b/test/src/config.ts new file mode 100644 index 00000000..9dec5966 --- /dev/null +++ b/test/src/config.ts @@ -0,0 +1,25 @@ +import { Porto } from 'porto' +import { custom, defineChain } from 'viem' +import * as chains from 'viem/chains' + +import { anvilMainnet } from './anvil.js' + +export const anvil = defineChain({ + ...chains.mainnet, + contracts: { + ...chains.mainnet.contracts, + accountDelegation: { + address: '0x0ff027b63351364071425cF65d4FEce75a8e17B8', + }, + }, + rpcUrls: { + default: { http: [anvilMainnet.rpcUrl] }, + }, +}) + +export const porto = Porto.create({ + chains: [anvil], + transports: { + [anvil.id]: custom(anvilMainnet), + }, +}) diff --git a/test/vitest.config.ts b/test/vitest.config.ts index 7c415e71..ffbca954 100644 --- a/test/vitest.config.ts +++ b/test/vitest.config.ts @@ -3,9 +3,13 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { + alias: { + porto: join(__dirname, '../src'), + }, globalSetup: [join(__dirname, './globalSetup.ts')], include: ['src/**/*.test.ts'], passWithNoTests: true, setupFiles: [join(__dirname, './setup.ts')], + testTimeout: 10_000, }, }) diff --git a/tsconfig.json b/tsconfig.json index 4f1d1ced..22b8f5df 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,12 @@ { // This configuration is used for local development and type checking. "extends": "./tsconfig.base.json", - "include": ["scripts", "src"], + "include": ["scripts", "src", "test"], "exclude": ["src/_dist"], "compilerOptions": { - "baseUrl": "." + "baseUrl": ".", + "paths": { + "porto": ["src/index.ts"] + } } }