diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml index 97c27648..0d699ee8 100644 --- a/.github/actions/install-dependencies/action.yml +++ b/.github/actions/install-dependencies/action.yml @@ -7,7 +7,7 @@ runs: - name: Set up Bun uses: oven-sh/setup-bun@v1 with: - bun-version: 1.0.26 + bun-version: 1.0.30 - name: Set up foundry uses: foundry-rs/foundry-toolchain@v1 diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 86696d0e..eb171f1f 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -25,19 +25,16 @@ jobs: - name: Install dependencies uses: ./.github/actions/install-dependencies + - uses: actions/setup-node@v4 + with: + node-version: "v22.2.0" + - name: Build run: bun run build:permissionless - - name: Start Docker - run: docker compose -f "packages/permissionless-test/mock-aa-infra/docker-compose.yml" up -d - - name: Run tests & coverage run: bun run test:ci - - name: Stop containers - if: always() - run: docker compose -f "packages/permissionless-test/mock-aa-infra/docker-compose.yml" down - - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 env: diff --git a/biome.json b/biome.json index 9cc93617..b2665b47 100644 --- a/biome.json +++ b/biome.json @@ -39,7 +39,7 @@ "javascript": { "formatter": { "semicolons": "asNeeded", - "trailingComma": "none" + "trailingCommas": "none" } } } diff --git a/bun.lockb b/bun.lockb index 4e96d83c..201f4962 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 88afb04b..20257823 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,10 @@ { - "workspaces": ["packages/*"], + "workspaces": [ + "packages/permissionless", + "packages/wagmi", + "packages/wagmi-test-demo", + "packages/create-permissionless-app" + ], "private": true, "author": "Pimlico", "type": "module", @@ -18,13 +23,15 @@ "simple-git-hooks": "^2.9.0", "size-limit": "^9.0.0", "tslib": "^2.6.2", + "@pimlico/alto": "^0.0.4", + "prool": "^0.0.12", "typescript": "^5.2.2" }, "description": "", "keywords": [], "license": "MIT", "scripts": { - "build": "bun run build:permissionless && bun run build:wagmi", + "build": "bun run build:permissionless", "build:permissionless": "bun run clean:permissionless && bun run build:cjs && bun run build:esm && bun run build:types", "build:wagmi": "bun run clean:wagmi && bun run build:wagmi:cjs && bun run build:wagmi:esm && bun run build:wagmi:types", "build:cjs": "tsc --project ./tsconfig/tsconfig.permissionless.cjs.json && tsc-alias -p ./tsconfig/tsconfig.permissionless.cjs.json && printf '{\"type\":\"commonjs\"}' > ./packages/permissionless/_cjs/package.json", @@ -38,9 +45,9 @@ "changeset:version": "changeset version && bun install --lockfile-only", "format": "biome format . --write", "lint": "biome check .", - "lint:fix": "bun run lint --apply", - "test": "bun run --cwd packages/permissionless-test test", - "test:ci": "bun run --cwd packages/permissionless-test test:ci", + "lint:fix": "bun run lint --write", + "test": "vitest dev -c ./packages/permissionless/vitest.config.ts", + "test:ci": "CI=true && vitest -c ./packages/permissionless/vitest.config.ts --coverage --pool=forks", "wagmi-demo": "bun run --cwd packages/wagmi-demo dev", "build:wagmi:cjs": "tsc --project ./tsconfig/tsconfig.wagmi.cjs.json && tsc-alias -p ./tsconfig/tsconfig.wagmi.cjs.json && printf '{\"type\":\"commonjs\"}' > ./packages/wagmi/_cjs/package.json", "build:wagmi:esm": "tsc --project ./tsconfig/tsconfig.wagmi.esm.json && tsc-alias -p ./tsconfig/tsconfig.wagmi.esm.json && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./packages/wagmi/_esm/package.json", @@ -51,7 +58,9 @@ "pre-commit": "bun run format && bun run lint:fix" }, "dependencies": { + "async-mutex": "^0.5.0", "get-port": "^7.0.0", - "tsc-alias": "^1.8.8" + "tsc-alias": "^1.8.8", + "viem": "^2.13.8" } } diff --git a/packages/permissionless-test/README.md b/packages/permissionless-test/README.md deleted file mode 100644 index b644187d..00000000 --- a/packages/permissionless-test/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Docker E2E Tests - -Permissionless E2E tests. - -#### Running tests locally - -setup a mock environment with: -```console -docker compose up -d -``` - -run test with: -```console -bun run test -``` - -#### Running github workflow locally -```console -act -W .github/workflows/on-pull-request.yml -``` - -#### Directory Breakdown -``` -mock-aa-infra/ => mock paymaster and alto instance -src/ => test cases found here -``` - -#### Adding new tests -Add a new entry to either `src/ep-0.6/coreSmartClientActions.test.ts` and or `src/ep-0.7/coreSmartClientActions.test.ts` to ensure that the new smart account handles all core functions. diff --git a/packages/permissionless-test/mock-aa-infra/alto/.dockerignore b/packages/permissionless-test/mock-aa-infra/alto/.dockerignore deleted file mode 100644 index 31dd108b..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/* -pnpm-lock.yaml diff --git a/packages/permissionless-test/mock-aa-infra/alto/Dockerfile b/packages/permissionless-test/mock-aa-infra/alto/Dockerfile deleted file mode 100644 index ca400b66..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# production ready dockerfile that runs pnpm start -FROM node:20-alpine - -# set working directory -WORKDIR /app - -# Install additional dependencies -RUN apk add --no-cache git - -# install pnpm -RUN npm install -g pnpm@^8.15 - -# copy source code -COPY . . - -# install dependencies -RUN pnpm fetch -RUN pnpm install - -# start app -ENTRYPOINT ["pnpm", "run", "start"] diff --git a/packages/permissionless-test/mock-aa-infra/alto/alto-config.json b/packages/permissionless-test/mock-aa-infra/alto/alto-config.json deleted file mode 100644 index 11351372..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/alto-config.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "network-name": "local", - "log-environment": "production", - "entrypoints": "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789,0x0000000071727De22E5E9d8BAf0edAc6f37da032", - "balance-override-enabled": "true", - "entrypoint-simulation-contract": "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87", - "api-version": "v1,v2", - "rpc-url": "http://anvil:8545", - "min-balance": "0", - "utility-private-key": "0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", - "executor-private-keys": "0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6,0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356,0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e,0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba,0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", - "max-block-range": 10000, - "safe-mode": false, - "port": 4337, - "log-level": "fatal", - "public-client-log-level": "error", - "wallet-client-log-level": "error", - "polling-interval": 100 -} diff --git a/packages/permissionless-test/mock-aa-infra/alto/src/constants.ts b/packages/permissionless-test/mock-aa-infra/alto/constants.ts similarity index 99% rename from packages/permissionless-test/mock-aa-infra/alto/src/constants.ts rename to packages/permissionless-test/mock-aa-infra/alto/constants.ts index 2d95af2f..e1dfbe94 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/src/constants.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/constants.ts @@ -67,7 +67,7 @@ export const BICONOMY_SINGLETON_FACTORY_BYTECODE: Hex = "0x608060405234801561001057600080fd5b50600436106100365760003560e01c8063bb34534c1461003b578063cdcb760a1461006a575b600080fd5b61004e61004936600461033f565b61007f565b6040516001600160a01b03909116815260200160405180910390f35b61007d610078366004610358565b610090565b005b600061008a8261010f565b92915050565b60006100d28484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506101fe92505050565b6040519091506001600160a01b038216907f8ffcdc15a283d706d38281f500270d8b5a656918f555de0913d7455e3e6bc1bf90600090a250505050565b6000806101a8836040517fff0000000000000000000000000000000000000000000000000000000000000060208201526bffffffffffffffffffffffff193060601b166021820152603581018290527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f605582015260009060750160408051601f19818403018152919052805160209091012092915050565b6040516135a560f21b60208201526bffffffffffffffffffffffff19606083901b166022820152600160f81b603682015290915060370160408051601f1981840301815291905280516020909101209392505050565b600061020c83836000610213565b9392505050565b60408051808201909152601081527f67363d3d37363d34f03d5260086018f30000000000000000000000000000000060208201526000906102538561010f565b9150813b156102755760405163cd43efa160e01b815260040160405180910390fd5b6000858251602084016000f590506001600160a01b0381166102aa5760405163bbd2fe8760e01b815260040160405180910390fd5b6000816001600160a01b031685876040516102c591906103d4565b60006040518083038185875af1925050503d8060008114610302576040519150601f19603f3d011682016040523d82523d6000602084013e610307565b606091505b505090508015806103175750833b155b15610335576040516353de54b960e01b815260040160405180910390fd5b5050509392505050565b60006020828403121561035157600080fd5b5035919050565b60008060006040848603121561036d57600080fd5b83359250602084013567ffffffffffffffff8082111561038c57600080fd5b818601915086601f8301126103a057600080fd5b8135818111156103af57600080fd5b8760208285010111156103c157600080fd5b6020830194508093505050509250925092565b6000825160005b818110156103f557602081860181015185830152016103db565b50600092019182525091905056fea26469706673582212207886676dff8e9b5ec182bd3d55512921e83b71170648ce1692043a572fa2954964736f6c63430008110033" // Will deploy V0.6 BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE to 0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e -export const BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL: Hex = +export const BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL: Hex = "0xcdcb760aa141e6dec8c9b10eb36022b4f82d2ffe43a3b172ad899d71e2dd80b0ee4c5b7c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000090960808060405234610016576108ed908161001c8239f35b600080fdfe6040608081526004908136101561001557600080fd5b6000803560e01c80631626ba7e146104065780632ede3bc014610384578063715018a614610314578063a3f4df7e146102c1578063f2fde38b1461020b578063f44c339d14610183578063fa5441611461012b578063ffa1ad74146100d45763fff35b721461008357600080fd5b346100cd576003199082823601126100cd5783359167ffffffffffffffff83116100d0576101609083360301126100cd57506020926100c6916024359101610543565b9051908152f35b80fd5b5080fd5b5090346100d057816003193601126100d057610127906100f2610446565b90600582527f302e322e30000000000000000000000000000000000000000000000000000000602083015251918291826104fa565b0390f35b5082346100d05760203660031901126100d0576001600160a01b0383816101506104e4565b16938481528060205220541691821561016d576020838551908152f35b8351633d3fff5360e21b81529182015260249150fd5b5091346102075760603660031901126102075760243567ffffffffffffffff8111610203576101b5903690830161047c565b90604435936001600160a01b03851685036100cd5750926101d991602094356105d8565b90517fffffffff000000000000000000000000000000000000000000000000000000009091168152f35b8380fd5b8280fd5b50919034610207576020366003190112610207576102276104e4565b803b6102a2576001600160a01b0380911692831561029457503384528360205281842054169083208273ffffffffffffffffffffffffffffffffffffffff19825416179055337fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8480a480f35b82516307e179e960e31b8152fd5b826001600160a01b0360249351926377817ac360e01b84521690820152fd5b5090346100d057816003193601126100d057610127906102df610446565b90601f82527f4543445341204f776e657273686970205265676973747279204d6f64756c6500602083015251918291826104fa565b50809134610381578160031936011261038157338252816020526001600160a01b03818320541690822073ffffffffffffffffffffffffffffffffffffffff198154169055337fc8894f26f396ce8c004245c8b7cd1b92103a6e4302fcbab883987149ac01b7ec8380a480f35b50fd5b5091346102075760203660031901126102075761039f6104e4565b338452836020526001600160a01b03908184862054166103f05716908115610294575081602093338152808552209073ffffffffffffffffffffffffffffffffffffffff1982541617905551308152f35b8351632c4dfb7d60e21b81523381850152602490fd5b50346100cd57816003193601126100cd576024359067ffffffffffffffff82116100cd575060209261043e6101d9923690830161047c565b3391356105d8565b604051906040820182811067ffffffffffffffff82111761046657604052565b634e487b7160e01b600052604160045260246000fd5b81601f820112156104df5780359067ffffffffffffffff928383116104665760405193601f8401601f19908116603f011685019081118582101761046657604052828452602083830101116104df57816000926020809301838601378301015290565b600080fd5b600435906001600160a01b03821682036104df57565b6020808252825181830181905290939260005b82811061052f57505060409293506000838284010152601f8019910116010190565b81810186015184820160400152850161050d565b610140810135601e19823603018112156104df57810167ffffffffffffffff81358181116104df57602083019080360382136104df578301906040848303126104df57359182116104df576040916020806105a293019185010161047c565b910135916001600160a01b0392838116036104df573591821682036104df576105ca92610616565b6105d357600190565b600090565b906105e39291610616565b61060b577fffffffff0000000000000000000000000000000000000000000000000000000090565b630b135d3f60e11b90565b916001600160a01b038091169160009383855284602052826040862054169384156106c4575060418251106106b2577f19457468657265756d205369676e6564204d6573736167653a0a333200000000855280601c528261068561067d84603c89206107f6565b9190916106dc565b1684146106a8576106999161067d916107f6565b16146106a25790565b50600190565b5050505050600190565b604051632bb1a9c560e11b8152600490fd5b60249060405190633d3fff5360e21b82526004820152fd5b60058110156107e057806106ed5750565b6001810361073a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606490fd5b600281036107875760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606490fd5b60031461079057565b60405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608490fd5b634e487b7160e01b600052602160045260246000fd5b90604181511460001461082457610820916020820151906060604084015193015160001a9061082e565b9091565b5050600090600290565b9291907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083116108ab5791608094939160ff602094604051948552168484015260408301526060820152600093849182805260015afa1561089e5781516001600160a01b038116156106a2579190565b50604051903d90823e3d90fd5b5050505060009060039056fea2646970667358221220d77d1372dac830175d3da0f00a91bc884b7cab72695fa25594e2902bca4a7bd964736f6c634300081100330000000000000000000000000000000000000000000000" // Will deploy V0.6 BICONOMY_ACCOUNT_V2_0_LOGIC to 0x0000002512019Dafb59528B82CB92D3c5D2423ac diff --git a/packages/permissionless-test/mock-aa-infra/alto/src/index.ts b/packages/permissionless-test/mock-aa-infra/alto/index.ts similarity index 67% rename from packages/permissionless-test/mock-aa-infra/alto/src/index.ts rename to packages/permissionless-test/mock-aa-infra/alto/index.ts index d59de276..8f60913a 100644 --- a/packages/permissionless-test/mock-aa-infra/alto/src/index.ts +++ b/packages/permissionless-test/mock-aa-infra/alto/index.ts @@ -1,11 +1,11 @@ import { http, type Address, + type PublicClient, createPublicClient, createTestClient, createWalletClient, - parseEther, - zeroAddress + parseEther } from "viem" import { mnemonicToAccount } from "viem/accounts" import { sendTransaction } from "viem/actions" @@ -13,7 +13,7 @@ import { foundry } from "viem/chains" import { BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, - BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL, + BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, BICONOMY_FACTORY_CREATECALL, BICONOMY_SINGLETON_FACTORY_BYTECODE, ENTRY_POINT_SIMULATIONS_CREATECALL, @@ -50,8 +50,10 @@ import { const DETERMINISTIC_DEPLOYER = "0x4e59b44847b379578588920ca78fbf26c0b4956c" const SAFE_SINGLETON_FACTORY = "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7" const BICONOMY_SINGLETON_FACTORY = "0x988C135a1049Ce61730724afD342fb7C56CD2776" +export const ENTRY_POINT_SIMULATIONS_ADDRESS = + "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87" -const verifyDeployed = async (addresses: Address[]) => { +const verifyDeployed = async (client: PublicClient, addresses: Address[]) => { for (const address of addresses) { const bytecode = await client.getBytecode({ address @@ -64,347 +66,241 @@ const verifyDeployed = async (addresses: Address[]) => { } } -const walletClient = createWalletClient({ - account: mnemonicToAccount( - "test test test test test test test test test test test junk" - ), - chain: foundry, - transport: http(process.env.ANVIL_RPC) -}) +export const setupContracts = async (rpc: string) => { + const walletClient = createWalletClient({ + account: mnemonicToAccount( + "test test test test test test test test test test test junk" + ), + chain: foundry, + transport: http(rpc) + }) -const anvilClient = createTestClient({ - transport: http(process.env.ANVIL_RPC), - mode: "anvil" -}) + const anvilClient = createTestClient({ + transport: http(rpc), + mode: "anvil" + }) -const client = createPublicClient({ - transport: http(process.env.ANVIL_RPC) -}) + const client = createPublicClient({ + transport: http(rpc) + }) -const main = async () => { - let nonce = 0 + let nonce = await client.getTransactionCount({ + address: walletClient.account.address + }) - walletClient - .sendTransaction({ + await Promise.all([ + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: ENTRY_POINT_V07_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying EntryPoint")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SIMPLE_ACCOUNT_FACTORY_V07_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying SimpleAccountFactory")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: ENTRY_POINT_SIMULATIONS_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[V0.7 CORE] Deploying EntryPointSimulations")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: ENTRY_POINT_V06_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[V0.6 CORE] Deploying EntryPoint")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SIMPLE_ACCOUNT_FACTORY_V06_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[V0.6 CORE] Deploying SimpleAccountFactory")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V06_MODULE_SETUP_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.6] Deploying Safe Module Setup")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V06_MODULE_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.6] Deploying Safe 4337 Module")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V07_MODULE_SETUP_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.7] Deploying Safe Module Setup")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: SAFE_V07_MODULE_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[SAFE V0.7] Deploying Safe 4337 Module")) - - await anvilClient - .setCode({ - address: SAFE_SINGLETON_FACTORY, - bytecode: SAFE_SINGLETON_FACTORY_BYTECODE - }) - .then(() => - console.log("[SAFE] Etched Safe Singleton Factory Bytecode") - ) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_PROXY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Proxy Factory")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_SINGLETON_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Singleton")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Multi Send")) - - walletClient - .sendTransaction({ - to: SAFE_SINGLETON_FACTORY, - data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[SAFE] Deploying Safe Multi Send Call Only")) - - await anvilClient - .setCode({ - address: BICONOMY_SINGLETON_FACTORY, - bytecode: BICONOMY_SINGLETON_FACTORY_BYTECODE - }) - .then(() => console.log("[BICONOMY] Etched Singleton Factory Bytecode")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MOUDULE_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => - console.log("[BICONOMY] Deployed ECDSA Ownership Registry Module") - ) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[BICONOMY] Deploying Account V0.2 Logic")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_FACTORY_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => console.log("[BICONOMY] Deploying Factory")) - - walletClient - .sendTransaction({ - to: BICONOMY_SINGLETON_FACTORY, - data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, - gas: 15_000_000n, - nonce: nonce++ - }) - .then(() => - console.log("[BICONOMY] Deploying Default Fallback Handler") - ) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V06_ECDSA_VALIDATOR_V2_2_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 ECDSA Validator")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V06_ACCOUNT_V2_2_LOGIC_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 Account V2 Logic")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V06_FACTORY_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.6 Factory")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V07_FACTORY_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 Factory")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V07_ECDSA_VALIDATOR_V3_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 ECDSA VALIDATOR")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V07_ACCOUNT_V3_LOGIC_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 ACCOUNT V3 LOGIC ")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: KERNEL_V07_META_FACTORY_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[KERNEL] Deploying V0.7 META FACTORY")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: LIGHT_ACCOUNT_FACTORY_V110_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => - console.log("[LIGHT ACCOUNT] Deploying v1.1.0 LightAccount Factory") - ) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_FACTORY_V06_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[TRUST] Deploying V0.6 Trust Factory")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_SECP256K1_VERIFICATION_FACET_CREATECALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => - console.log("[TRUST] Deploying Trust Secp256k1 Verification Facet") - ) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_ACCOUNT_FACET_CREATE_CALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[TRUST] Deploying Trust AccountFacet")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_DIAMOND_CUT_FACET_CREATE_CALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[TRUST] Deploying Trust DiamondCutFacet")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_TOKEN_RECEIVER_FACET_CREATE_CALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[TRUST] Deploying Trust TokenReceiverFacet")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_DIAMOND_LOUPE_FACET_CREATE_CALL, gas: 15_000_000n, nonce: nonce++ - }) - .then(() => console.log("[TRUST] Deploying Trust DiamondLoupeFacet")) - - walletClient - .sendTransaction({ + }), + walletClient.sendTransaction({ to: DETERMINISTIC_DEPLOYER, data: TRUST_DEFAULT_FALLBACK_HANDLER, gas: 15_000_000n, nonce: nonce++ }) - .then(() => - console.log("[TRUST] Deploying Trust default fallback handler") - ) + ]) + + await anvilClient.setCode({ + address: SAFE_SINGLETON_FACTORY, + bytecode: SAFE_SINGLETON_FACTORY_BYTECODE + }) - let onchainNonce = 0 - do { - onchainNonce = await client.getTransactionCount({ - address: walletClient.account.address + await Promise.all([ + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_PROXY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_SINGLETON_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + walletClient.sendTransaction({ + to: SAFE_SINGLETON_FACTORY, + data: SAFE_MULTI_SEND_CALL_ONLY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }) + ]) + + await anvilClient.setCode({ + address: BICONOMY_SINGLETON_FACTORY, + bytecode: BICONOMY_SINGLETON_FACTORY_BYTECODE + }) + + await Promise.all([ + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ECDSA_OWNERSHIP_REGISTRY_MODULE_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_ACCOUNT_V2_LOGIC_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_FACTORY_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ + }), + + walletClient.sendTransaction({ + to: BICONOMY_SINGLETON_FACTORY, + data: BICONOMY_DEFAULT_FALLBACK_HANDLER_CREATECALL, + gas: 15_000_000n, + nonce: nonce++ }) - await new Promise((resolve) => setTimeout(resolve, 500)) - } while (onchainNonce !== nonce) + ]) // ==== SETUP KERNEL V0.6 CONTRACTS ==== // const kernelFactoryOwner = "0x9775137314fE595c943712B0b336327dfa80aE8A" @@ -463,13 +359,13 @@ const main = async () => { address: alchemyLightClientOwner }) - await verifyDeployed([ + await verifyDeployed(client, [ "0x4e59b44847b379578588920ca78fbf26c0b4956c", // Determinstic deployer "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7", // Safe Singleton Factory "0x988C135a1049Ce61730724afD342fb7C56CD2776", // Biconomy Singleton Factory "0x0000000071727De22E5E9d8BAf0edAc6f37da032", // EntryPoint v0.7 "0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985", // Simple Account Factory V0.7 - "0x74Cb5e4eE81b86e70f9045036a1C5477de69eE87", // EntryPoint Simulations (Needed for v0.7) + ENTRY_POINT_SIMULATIONS_ADDRESS, // EntryPoint Simulations (Needed for v0.7) "0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47", // Safe V0.7 Module Setup "0x75cf11467937ce3F2f357CE24ffc3DBF8fD5c226", // Safe V0.7 4337 Module "0x8EcD4ec46D4D2a6B64fE960B3D64e8B94B2234eb", // Safe V0.6 Module Setup @@ -493,7 +389,6 @@ const main = async () => { "0xd703aaE79538628d27099B8c4f621bE4CCd142d5", // Kernel v0.3.0 Meta Factory "0x00004EC70002a32400f8ae005A26081065620D20", // LightAccountFactory v1.1.0 "0xae8c656ad28F2B59a196AB61815C16A0AE1c3cba", // LightAccount v1.1.0 implementation - "0x81b9E3689390C7e74cF526594A105Dea21a8cdD5", // Trust Secp256k1VerificationFacet "0x729c310186a57833f622630a16d13f710b83272a", // Trust factory "0xFde53272dcd7938d16E031A6989753c321728332", // Trust AccountFacet @@ -503,5 +398,3 @@ const main = async () => { "0x2e7f1dAe1F3799d20f5c31bEFdc7A620f664728D" // Trust DefaultFallbackHandler ]) } - -main() diff --git a/packages/permissionless-test/mock-aa-infra/alto/package.json b/packages/permissionless-test/mock-aa-infra/alto/package.json deleted file mode 100644 index 774a824d..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "alto + contract-deployer", - "private": true, - "scripts": { - "start": "pnpm run start:deploy-contracts && pnpm run install:alto && pnpm run start:alto", - "install:alto": "cd node_modules/alto && pnpm install", - "start:deploy-contracts": "wait-port anvil:8545 && ts-node src/index.ts", - "start:alto": "pnpm alto run --config ./alto-config.json" - }, - "dependencies": { - "alto": "github:pimlicolabs/alto", - "alto + contract-deployer": "link:", - "viem": "^2.9.9" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "ts-node": "^10.9.2", - "wait-port": "^1.1.0" - } -} diff --git a/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml b/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml deleted file mode 100644 index 2e528783..00000000 --- a/packages/permissionless-test/mock-aa-infra/alto/pnpm-lock.yaml +++ /dev/null @@ -1,324 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - alto: - specifier: github:pimlicolabs/alto - version: github.com/pimlicolabs/alto/459e9a526a9859f1fd269f9b920f008255ce7bfb - alto + contract-deployer: - specifier: 'link:' - version: 'link:' - viem: - specifier: ^2.9.9 - version: 2.9.23(typescript@5.4.5) - -devDependencies: - '@types/node': - specifier: ^20.12.4 - version: 20.12.7 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.7)(typescript@5.4.5) - wait-port: - specifier: ^1.1.0 - version: 1.1.0 - -packages: - - /@adraffy/ens-normalize@1.10.0: - resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} - dev: false - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@noble/curves@1.2.0: - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - dependencies: - '@noble/hashes': 1.3.2 - dev: false - - /@noble/hashes@1.3.2: - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - dev: false - - /@scure/base@1.1.6: - resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} - dev: false - - /@scure/bip32@1.3.2: - resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} - dependencies: - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@scure/bip39@1.2.1: - resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} - dependencies: - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - - /@types/node@20.12.7: - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} - dependencies: - undici-types: 5.26.5 - dev: true - - /abitype@1.0.0(typescript@5.4.5): - resolution: {integrity: sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - dependencies: - typescript: 5.4.5 - dev: false - - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - dev: true - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /isows@1.0.3(ws@8.13.0): - resolution: {integrity: sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg==} - peerDependencies: - ws: '*' - dependencies: - ws: 8.13.0 - dev: false - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.5): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 - acorn: 8.11.3 - acorn-walk: 8.3.2 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.4.5 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - - /viem@2.9.23(typescript@5.4.5): - resolution: {integrity: sha512-KolNI8H8tNkOA6xkC5UnlQjoorJxk4F1F9h42pHnH9/CtrWG9Ka4xmAWwhO2xKNPA2sNsAsJLmedBsz2uvaQow==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 - abitype: 1.0.0(typescript@5.4.5) - isows: 1.0.3(ws@8.13.0) - typescript: 5.4.5 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - dev: false - - /wait-port@1.1.0: - resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} - engines: {node: '>=10'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 9.5.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - - github.com/pimlicolabs/alto/459e9a526a9859f1fd269f9b920f008255ce7bfb: - resolution: {tarball: https://codeload.github.com/pimlicolabs/alto/tar.gz/459e9a526a9859f1fd269f9b920f008255ce7bfb} - name: root - version: 0.0.1 - engines: {node: '>=18.0.0'} - hasBin: true - prepare: true - requiresBuild: true - dev: false diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile b/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile deleted file mode 100644 index 7fe17d6b..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# production ready dockerfile that runs pnpm start -FROM node:20-alpine - -# set working directory -WORKDIR /app - -# install pnpm -RUN npm install -g pnpm - -# copy package.json -COPY package.json ./ - -# copy source code -COPY ./src ./src - -# install dependencies -RUN pnpm fetch -RUN pnpm install - -# start app -ENTRYPOINT ["pnpm", "run", "start"] diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/abi.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/abi.ts similarity index 100% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/abi.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/abi.ts diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts similarity index 98% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts index 5bb14062..ca2290b8 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/schema.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/schema.ts @@ -1,5 +1,5 @@ import { type Hex, getAddress } from "viem" -import { type infer as zodInfer, z } from "zod" +import { z, type infer as zodInfer } from "zod" export enum ValidationErrors { InvalidFields = -32602, diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts similarity index 84% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts index 24877754..95cb8bad 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/utils.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/utils.ts @@ -2,7 +2,7 @@ import { http, createWalletClient } from "viem" import { mnemonicToAccount } from "viem/accounts" import { foundry } from "viem/chains" -export const getAnvilWalletClient = () => { +export const getAnvilWalletClient = (anvilRpc: string) => { const account = mnemonicToAccount( "test test test test test test test test test test test junk", { @@ -14,7 +14,7 @@ export const getAnvilWalletClient = () => { const walletClient = createWalletClient({ account, chain: foundry, - transport: http(process.env.ANVIL_RPC) + transport: http(anvilRpc) }) return walletClient diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts similarity index 96% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts index e4172d5e..85c87428 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/helpers/verifyingPaymasters.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/helpers/verifyingPaymasters.ts @@ -14,7 +14,6 @@ import { parseEther, slice } from "viem" -import { waitForTransactionReceipt } from "viem/actions" import { foundry } from "viem/chains" import { VERIFYING_PAYMASTER_V06_ABI, VERIFYING_PAYMASTER_V07_ABI } from "./abi" @@ -36,12 +35,13 @@ const VERIFYING_PAYMASTER_V06_CALL = (owner: Address): Hex => ]) export const setupVerifyingPaymasterV07 = async ( - walletClient: WalletClient + walletClient: WalletClient, + anvilRpc: string ) => { const data = VERIFYING_PAYMASTER_V07_CALL(walletClient.account.address) const publicClient = createPublicClient({ - transport: http(process.env.ANVIL_RPC), + transport: http(anvilRpc), chain: foundry }) @@ -51,7 +51,6 @@ export const setupVerifyingPaymasterV07 = async ( data }) .then((hash) => publicClient.waitForTransactionReceipt({ hash })) - .then(() => console.log("deployed VerifyingPaymaster v0.7")) const address = getContractAddress({ opcode: "CREATE2", @@ -66,22 +65,21 @@ export const setupVerifyingPaymasterV07 = async ( client: walletClient }) - await verifyingPaymaster.write - .deposit({ - value: parseEther("50") - }) - .then(() => console.log("Funded VerifyingPaymaster V0.7")) + await verifyingPaymaster.write.deposit({ + value: parseEther("50") + }) return verifyingPaymaster } export const setupVerifyingPaymasterV06 = async ( - walletClient: WalletClient + walletClient: WalletClient, + anvilRpc: string ) => { const data = VERIFYING_PAYMASTER_V06_CALL(walletClient.account.address) const publicClient = createPublicClient({ - transport: http(process.env.ANVIL_RPC), + transport: http(anvilRpc), chain: foundry }) @@ -91,7 +89,6 @@ export const setupVerifyingPaymasterV06 = async ( data }) .then((hash) => publicClient.waitForTransactionReceipt({ hash })) - .then(() => console.log("deployed VerifyingPaymaster v0.6")) const address = getContractAddress({ opcode: "CREATE2", @@ -106,11 +103,9 @@ export const setupVerifyingPaymasterV06 = async ( client: walletClient }) - await verifyingPaymaster.write - .deposit({ - value: parseEther("50") - }) - .then(() => console.log("Funded VerifyingPaymaster V0.6")) + await verifyingPaymaster.write.deposit({ + value: parseEther("50") + }) return verifyingPaymaster } diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts new file mode 100644 index 00000000..44321b33 --- /dev/null +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/index.ts @@ -0,0 +1,79 @@ +import cors from "@fastify/cors" +import Fastify from "fastify" +import { defineInstance } from "prool" +import { http } from "viem" +import { foundry } from "viem/chains" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07 +} from "../../../permissionless" +import { createPimlicoBundlerClient } from "../../../permissionless/clients/pimlico" +import { getAnvilWalletClient } from "./helpers/utils" +import { + setupVerifyingPaymasterV06, + setupVerifyingPaymasterV07 +} from "./helpers/verifyingPaymasters" +import { createRpcHandler } from "./relay" + +export const paymaster = defineInstance( + ({ + anvilRpc, + port: _port, + altoRpc + }: { anvilRpc: string; port: number; altoRpc: string }) => { + const app = Fastify({}) + + return { + _internal: {}, + host: "localhost", + port: _port, + name: "mock-paymaster", + start: async ({ port = _port }) => { + const walletClient = getAnvilWalletClient(anvilRpc) + const verifyingPaymasterV07 = await setupVerifyingPaymasterV07( + walletClient, + anvilRpc + ) + const verifyingPaymasterV06 = await setupVerifyingPaymasterV06( + walletClient, + anvilRpc + ) + + const altoBundlerV07 = createPimlicoBundlerClient({ + chain: foundry, + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const altoBundlerV06 = createPimlicoBundlerClient({ + chain: foundry, + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + app.register(cors, { + origin: "*", + methods: ["POST", "GET", "OPTIONS"] + }) + + const rpcHandler = createRpcHandler( + altoBundlerV07, + altoBundlerV06, + verifyingPaymasterV07, + verifyingPaymasterV06, + walletClient + ) + app.post("/", {}, rpcHandler) + + app.get("/ping", async (_request, reply) => { + return reply.code(200).send({ message: "pong" }) + }) + + await app.listen({ host: "localhost", port }) + }, + stop: async () => { + app.close() + } + } + } +) diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json b/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json deleted file mode 100644 index d581be87..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "mock-paymaster", - "private": true, - "scripts": { - "start": "wait-port anvil:8545 && ts-node src/index.ts" - }, - "dependencies": { - "@fastify/cors": "^9.0.1", - "fastify": "^4.26.2", - "permissionless": "^0.1.0", - "tslib": "^2.6.2", - "typescript": "5.4.2", - "viem": "2.7.12", - "zod": "^3.22.4", - "zod-validation-error": "^3.0.3" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "ts-node": "^10.9.2", - "wait-port": "^1.0.4" - } -} diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml b/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml deleted file mode 100644 index 1eea8e33..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/pnpm-lock.yaml +++ /dev/null @@ -1,765 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@fastify/cors': - specifier: ^9.0.1 - version: 9.0.1 - fastify: - specifier: ^4.26.2 - version: 4.26.2 - permissionless: - specifier: ^0.1.0 - version: 0.1.16(viem@2.7.12) - tslib: - specifier: ^2.6.2 - version: 2.6.2 - typescript: - specifier: 5.4.2 - version: 5.4.2 - viem: - specifier: 2.7.12 - version: 2.7.12(typescript@5.4.2)(zod@3.22.4) - zod: - specifier: ^3.22.4 - version: 3.22.4 - zod-validation-error: - specifier: ^3.0.3 - version: 3.1.0(zod@3.22.4) - -devDependencies: - '@types/node': - specifier: ^20.12.4 - version: 20.12.7 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.12.7)(typescript@5.4.2) - wait-port: - specifier: ^1.0.4 - version: 1.1.0 - -packages: - - /@adraffy/ens-normalize@1.10.0: - resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} - dev: false - - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - dev: true - - /@fastify/ajv-compiler@3.5.0: - resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} - dependencies: - ajv: 8.12.0 - ajv-formats: 2.1.1(ajv@8.12.0) - fast-uri: 2.3.0 - dev: false - - /@fastify/cors@9.0.1: - resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==} - dependencies: - fastify-plugin: 4.5.1 - mnemonist: 0.39.6 - dev: false - - /@fastify/error@3.4.1: - resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} - dev: false - - /@fastify/fast-json-stringify-compiler@4.3.0: - resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} - dependencies: - fast-json-stringify: 5.14.1 - dev: false - - /@fastify/merge-json-schemas@0.1.1: - resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} - dependencies: - fast-deep-equal: 3.1.3 - dev: false - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true - - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - - /@noble/curves@1.2.0: - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - dependencies: - '@noble/hashes': 1.3.2 - dev: false - - /@noble/hashes@1.3.2: - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - dev: false - - /@scure/base@1.1.6: - resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} - dev: false - - /@scure/bip32@1.3.2: - resolution: {integrity: sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==} - dependencies: - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@scure/bip39@1.2.1: - resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} - dependencies: - '@noble/hashes': 1.3.2 - '@scure/base': 1.1.6 - dev: false - - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true - - /@types/node@20.12.7: - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} - dependencies: - undici-types: 5.26.5 - dev: true - - /abitype@1.0.0(typescript@5.4.2)(zod@3.22.4): - resolution: {integrity: sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - dependencies: - typescript: 5.4.2 - zod: 3.22.4 - dev: false - - /abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - dependencies: - event-target-shim: 5.0.1 - dev: false - - /abstract-logging@2.0.1: - resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - dev: false - - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /ajv-formats@2.1.1(ajv@8.12.0): - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.12.0 - dev: false - - /ajv-formats@3.0.1(ajv@8.12.0): - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.12.0 - dev: false - - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: false - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - dev: false - - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true - - /atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - dev: false - - /avvio@8.3.0: - resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==} - dependencies: - '@fastify/error': 3.4.1 - archy: 1.0.0 - debug: 4.3.4 - fastq: 1.17.1 - transitivePeerDependencies: - - supports-color - dev: false - - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: false - - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: false - - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - dev: true - - /cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - dev: false - - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true - - /event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - dev: false - - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - dev: false - - /fast-content-type-parse@1.1.0: - resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} - dev: false - - /fast-decode-uri-component@1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - dev: false - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: false - - /fast-json-stringify@5.14.1: - resolution: {integrity: sha512-J1Grbf0oSXV3lKsBf3itz1AvRk43qVrx3Ac10sNvi3LZaz1by4oDdYKFrJycPhS8+Gb7y8rgV/Jqw1UZVjyNvw==} - dependencies: - '@fastify/merge-json-schemas': 0.1.1 - ajv: 8.12.0 - ajv-formats: 3.0.1(ajv@8.12.0) - fast-deep-equal: 3.1.3 - fast-uri: 2.3.0 - json-schema-ref-resolver: 1.0.1 - rfdc: 1.3.1 - dev: false - - /fast-querystring@1.1.2: - resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - dependencies: - fast-decode-uri-component: 1.0.1 - dev: false - - /fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - dev: false - - /fast-uri@2.3.0: - resolution: {integrity: sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==} - dev: false - - /fastify-plugin@4.5.1: - resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} - dev: false - - /fastify@4.26.2: - resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==} - dependencies: - '@fastify/ajv-compiler': 3.5.0 - '@fastify/error': 3.4.1 - '@fastify/fast-json-stringify-compiler': 4.3.0 - abstract-logging: 2.0.1 - avvio: 8.3.0 - fast-content-type-parse: 1.1.0 - fast-json-stringify: 5.14.1 - find-my-way: 8.1.0 - light-my-request: 5.13.0 - pino: 8.20.0 - process-warning: 3.0.0 - proxy-addr: 2.0.7 - rfdc: 1.3.1 - secure-json-parse: 2.7.0 - semver: 7.6.0 - toad-cache: 3.7.0 - transitivePeerDependencies: - - supports-color - dev: false - - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - dependencies: - reusify: 1.0.4 - dev: false - - /find-my-way@8.1.0: - resolution: {integrity: sha512-41QwjCGcVTODUmLLqTMeoHeiozbMXYMAE1CKFiDyi9zVZ2Vjh0yz3MF0WQZoIb+cmzP/XlbFjlF2NtJmvZHznA==} - engines: {node: '>=14'} - dependencies: - fast-deep-equal: 3.1.3 - fast-querystring: 1.1.2 - safe-regex2: 2.0.0 - dev: false - - /forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - dev: false - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false - - /ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - dev: false - - /isows@1.0.3(ws@8.13.0): - resolution: {integrity: sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg==} - peerDependencies: - ws: '*' - dependencies: - ws: 8.13.0 - dev: false - - /json-schema-ref-resolver@1.0.1: - resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} - dependencies: - fast-deep-equal: 3.1.3 - dev: false - - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: false - - /light-my-request@5.13.0: - resolution: {integrity: sha512-9IjUN9ZyCS9pTG+KqTDEQo68Sui2lHsYBrfMyVUTTZ3XhH8PMZq7xO94Kr+eP9dhi/kcKsx4N41p2IXEBil1pQ==} - dependencies: - cookie: 0.6.0 - process-warning: 3.0.0 - set-cookie-parser: 2.6.0 - dev: false - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: false - - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /mnemonist@0.39.6: - resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} - dependencies: - obliterator: 2.0.4 - dev: false - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - /obliterator@2.0.4: - resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - dev: false - - /on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} - dev: false - - /permissionless@0.1.16(viem@2.7.12): - resolution: {integrity: sha512-UGC3yJiGYcPHJ+LohSFJSIxQGIQ2DMREYXGwVtb0DdvTVuO+uqqEymD6LZnKdtLF2KGhBPODv37LqvRyh+ma3g==} - peerDependencies: - viem: ^2.0.0 - dependencies: - viem: 2.7.12(typescript@5.4.2)(zod@3.22.4) - dev: false - - /pino-abstract-transport@1.1.0: - resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} - dependencies: - readable-stream: 4.5.2 - split2: 4.2.0 - dev: false - - /pino-std-serializers@6.2.2: - resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} - dev: false - - /pino@8.20.0: - resolution: {integrity: sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==} - hasBin: true - dependencies: - atomic-sleep: 1.0.0 - fast-redact: 3.5.0 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.1.0 - pino-std-serializers: 6.2.2 - process-warning: 3.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.4.3 - sonic-boom: 3.8.1 - thread-stream: 2.4.1 - dev: false - - /process-warning@3.0.0: - resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} - dev: false - - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - dev: false - - /proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - dev: false - - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: false - - /quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - dev: false - - /readable-stream@4.5.2: - resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - dev: false - - /real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} - dev: false - - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: false - - /ret@0.2.2: - resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} - engines: {node: '>=4'} - dev: false - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: false - - /rfdc@1.3.1: - resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} - dev: false - - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false - - /safe-regex2@2.0.0: - resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} - dependencies: - ret: 0.2.2 - dev: false - - /safe-stable-stringify@2.4.3: - resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} - engines: {node: '>=10'} - dev: false - - /secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - dev: false - - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: false - - /set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} - dev: false - - /sonic-boom@3.8.1: - resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} - dependencies: - atomic-sleep: 1.0.0 - dev: false - - /split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - dev: false - - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - dev: false - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /thread-stream@2.4.1: - resolution: {integrity: sha512-d/Ex2iWd1whipbT681JmTINKw0ZwOUBZm7+Gjs64DHuX34mmw8vJL2bFAaNacaW72zYiTJxSHi5abUuOi5nsfg==} - dependencies: - real-require: 0.2.0 - dev: false - - /toad-cache@3.7.0: - resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} - engines: {node: '>=12'} - dev: false - - /ts-node@10.9.2(@types/node@20.12.7)(typescript@5.4.2): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.12.7 - acorn: 8.11.3 - acorn-walk: 8.3.2 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.4.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: false - - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - dev: false - - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true - - /viem@2.7.12(typescript@5.4.2)(zod@3.22.4): - resolution: {integrity: sha512-NbV+Bycw0I4X8y6A04mgJ6+Imt7xXwflgnqisR3JXoJRNc77YSaQCscFN/dmwGLESTkgegJvi+j4nZY32GTpwQ==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@adraffy/ens-normalize': 1.10.0 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@scure/bip32': 1.3.2 - '@scure/bip39': 1.2.1 - abitype: 1.0.0(typescript@5.4.2)(zod@3.22.4) - isows: 1.0.3(ws@8.13.0) - typescript: 5.4.2 - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - dev: false - - /wait-port@1.1.0: - resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} - engines: {node: '>=10'} - hasBin: true - dependencies: - chalk: 4.1.2 - commander: 9.5.0 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: false - - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true - - /zod-validation-error@3.1.0(zod@3.22.4): - resolution: {integrity: sha512-zujS6HqJjMZCsvjfbnRs7WI3PXN39ovTcY1n8a+KTm4kOH0ZXYsNiJkH1odZf4xZKMkBDL7M2rmQ913FCS1p9w==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.18.0 - dependencies: - zod: 3.22.4 - dev: false - - /zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - dev: false diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/relay.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts similarity index 97% rename from packages/permissionless-test/mock-aa-infra/mock-paymaster/src/relay.ts rename to packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts index 849c3dc4..299687eb 100644 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/relay.ts +++ b/packages/permissionless-test/mock-aa-infra/mock-paymaster/relay.ts @@ -1,17 +1,5 @@ import util from "node:util" import type { FastifyReply, FastifyRequest } from "fastify" -import { - ENTRYPOINT_ADDRESS_V07, - type EstimateUserOperationGasReturnType, - getPackedUserOperation -} from "permissionless" -import type { PimlicoBundlerClient } from "permissionless/clients/pimlico" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - ENTRYPOINT_ADDRESS_V07_TYPE, - UserOperation -} from "permissionless/types" -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless/utils" import { type Account, BaseError, @@ -27,6 +15,18 @@ import { toHex } from "viem" import { fromZodError } from "zod-validation-error" +import { + ENTRYPOINT_ADDRESS_V07, + type EstimateUserOperationGasReturnType, + getPackedUserOperation +} from "../../../permissionless" +import type { PimlicoBundlerClient } from "../../../permissionless/clients/pimlico" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, + UserOperation +} from "../../../permissionless/types" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless/utils" import type { VERIFYING_PAYMASTER_V06_ABI, VERIFYING_PAYMASTER_V07_ABI @@ -295,8 +295,6 @@ export const createRpcHandler = ( walletClient: WalletClient ) => { return async (request: FastifyRequest, _reply: FastifyReply) => { - console.log(`received request: ${JSON.stringify(request.body)}`) - const body = request.body const parsedBody = jsonRpcSchema.safeParse(body) if (!parsedBody.success) { diff --git a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts b/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts deleted file mode 100644 index de16703a..00000000 --- a/packages/permissionless-test/mock-aa-infra/mock-paymaster/src/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import cors from "@fastify/cors" -import Fastify from "fastify" -import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "permissionless" -import { createPimlicoBundlerClient } from "permissionless/clients/pimlico" -import { http } from "viem" -import { foundry } from "viem/chains" -import { getAnvilWalletClient } from "./helpers/utils" -import { - setupVerifyingPaymasterV06, - setupVerifyingPaymasterV07 -} from "./helpers/verifyingPaymasters" -import { createRpcHandler } from "./relay" - -const main = async () => { - const walletClient = getAnvilWalletClient() - const verifyingPaymasterV07 = await setupVerifyingPaymasterV07(walletClient) - const verifyingPaymasterV06 = await setupVerifyingPaymasterV06(walletClient) - - const altoBundlerV07 = createPimlicoBundlerClient({ - chain: foundry, - transport: http(process.env.ALTO_RPC), - entryPoint: ENTRYPOINT_ADDRESS_V07 - }) - - const altoBundlerV06 = createPimlicoBundlerClient({ - chain: foundry, - transport: http(process.env.ALTO_RPC), - entryPoint: ENTRYPOINT_ADDRESS_V06 - }) - - const app = Fastify({}) - - app.register(cors, { - origin: "*", - methods: ["POST", "GET", "OPTIONS"] - }) - - const rpcHandler = createRpcHandler( - altoBundlerV07, - altoBundlerV06, - verifyingPaymasterV07, - verifyingPaymasterV06, - walletClient - ) - app.post("/", {}, rpcHandler) - - app.get("/ping", async (_request, reply) => { - return reply.code(200).send({ message: "pong" }) - }) - - await app.listen({ host: "0.0.0.0", port: 3000 }) -} - -main() diff --git a/packages/permissionless-test/package.json b/packages/permissionless-test/package.json deleted file mode 100644 index 8acbd44a..00000000 --- a/packages/permissionless-test/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "test-cases", - "version": "0.0.0", - "type": "module", - "private": true, - "scripts": { - "start": "bun run wait-for-setup && pnpm run test", - "wait-for-setup": "wait-port localhost:4337", - "test": "bun run wait-for-setup && vitest dev -c ./vitest.config.ts", - "test:ci": "CI=true && bun run wait-for-setup && vitest -c ./vitest.config.ts --coverage --pool=forks" - }, - "dependencies": { - "tslib": "^2.6.2", - "viem": "^2.9.17", - "permissionless": "workspace:packages/permissionless" - }, - "devDependencies": { - "@types/node": "^20.12.4", - "@vitest/coverage-v8": "^1.2.0", - "ts-node": "^10.9.2", - "vitest": "^1.5.2", - "wait-port": "^1.1.0" - } -} diff --git a/packages/permissionless-test/src/common/utils.test.ts b/packages/permissionless-test/src/common/utils.test.ts index 896dbba7..4b62212f 100644 --- a/packages/permissionless-test/src/common/utils.test.ts +++ b/packages/permissionless-test/src/common/utils.test.ts @@ -1,17 +1,3 @@ -import { - ENTRYPOINT_ADDRESS_V06, - ENTRYPOINT_ADDRESS_V07, - type GetSenderAddressParams, - deepHexlify, - getSenderAddress, - getUserOperationHash -} from "permissionless" -import type { PackedUserOperation } from "permissionless/types" -import { - getPackedUserOperation, - getRequiredPrefund, - signUserOperationHashWithECDSA -} from "permissionless/utils" import { type Address, type Hash, @@ -25,6 +11,20 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, expectTypeOf, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07, + type GetSenderAddressParams, + deepHexlify, + getSenderAddress, + getUserOperationHash +} from "../../../permissionless" +import type { PackedUserOperation } from "../../../permissionless/types" +import { + getPackedUserOperation, + getRequiredPrefund, + signUserOperationHashWithECDSA +} from "../../../permissionless/utils" import { SIMPLE_ACCOUNT_FACTORY_V06, SIMPLE_ACCOUNT_FACTORY_V07 diff --git a/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts b/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts index 52a4cb97..716a31a1 100644 --- a/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/bundlerActions.test.ts @@ -1,18 +1,18 @@ +import { type Chain, isHash, zeroAddress } from "viem" +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" import { type BundlerClient, WaitForUserOperationReceiptTimeoutError -} from "permissionless" +} from "../../../permissionless" import type { ENTRYPOINT_ADDRESS_V06_TYPE, UserOperation -} from "permissionless/types" +} from "../../../permissionless/types" import { ENTRYPOINT_ADDRESS_V06, getUserOperationHash -} from "permissionless/utils" -import { type Chain, isHash, zeroAddress } from "viem" -import { foundry } from "viem/chains" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless/utils" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts b/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts index 28d71ef8..9b6754b7 100644 --- a/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/coreSmartClientActions.test.ts @@ -1,20 +1,3 @@ -import { - type BundlerClient, - ENTRYPOINT_ADDRESS_V06, - createSmartAccountClient -} from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToBiconomySmartAccount, - signerToEcdsaKernelSmartAccount, - signerToLightSmartAccount, - signerToSafeSmartAccount, - signerToSimpleSmartAccount, - signerToTrustSmartAccount -} from "permissionless/accounts" -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" -import { getUserOperationHash } from "permissionless/utils" import { http, type BaseError, @@ -32,11 +15,27 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, test } from "vitest" +import { + type BundlerClient, + ENTRYPOINT_ADDRESS_V06, + createSmartAccountClient +} from "../../../permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToBiconomySmartAccount, + signerToEcdsaKernelSmartAccount, + signerToLightSmartAccount, + signerToSafeSmartAccount, + signerToSimpleSmartAccount, + signerToTrustSmartAccount +} from "../../../permissionless/accounts" +import type { PimlicoPaymasterClient } from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" +import { getUserOperationHash } from "../../../permissionless/utils" import { ENTRYPOINT_V06_ABI } from "../../abi/entryPointV06Abi" import { SIMPLE_ACCOUNT_FACTORY_V06 } from "../constants" import type { AAParamType, ExistingSignerParamType } from "../types" import { - ALTO_RPC, ensureBundlerIsReady, ensurePaymasterIsReady, fund, diff --git a/packages/permissionless-test/src/ep-0.6/experiments.ts b/packages/permissionless-test/src/ep-0.6/experiments.ts index 811bef4b..191f88b7 100644 --- a/packages/permissionless-test/src/ep-0.6/experiments.ts +++ b/packages/permissionless-test/src/ep-0.6/experiments.ts @@ -1,14 +1,14 @@ -import { - ENTRYPOINT_ADDRESS_V06, - createSmartAccountClient -} from "permissionless" -import { privateKeyToSafeSmartAccount } from "permissionless/accounts" -import { paymasterActionsEip7677 } from "permissionless/experimental" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { http, createClient, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { foundry } from "viem/chains" import { describe, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V06, + createSmartAccountClient +} from "../../../permissionless" +import { privateKeyToSafeSmartAccount } from "../../../permissionless/accounts" +import { paymasterActionsEip7677 } from "../../../permissionless/experimental" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" import type { AAParamType } from "../types" import { PAYMASTER_RPC, diff --git a/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts b/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts index bda1718a..54cfd87f 100644 --- a/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts +++ b/packages/permissionless-test/src/ep-0.6/pimlicoActions.test.ts @@ -1,9 +1,3 @@ -import type { PimlicoBundlerClient } from "permissionless/clients/pimlico" -import type { - ENTRYPOINT_ADDRESS_V06_TYPE, - UserOperation -} from "permissionless/types" -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless/utils" import { type Chain, type PublicClient, @@ -12,6 +6,12 @@ import { isHex } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import type { PimlicoBundlerClient } from "../../../permissionless/clients/pimlico" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + UserOperation +} from "../../../permissionless/types" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless/utils" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts b/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts index 4f44aa98..ea031a92 100644 --- a/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts +++ b/packages/permissionless-test/src/ep-0.6/safeSmartAccount.test.ts @@ -1,6 +1,6 @@ -import { ENTRYPOINT_ADDRESS_V06 } from "permissionless" import { isHash, zeroAddress } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V06 } from "../../../permissionless" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts b/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts index 914f3b1d..12468ff1 100644 --- a/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/bundlerActions.test.ts @@ -1,14 +1,14 @@ +import { type Chain, isHash } from "viem" +import { foundry } from "viem/chains" +import { beforeAll, describe, expect, test } from "vitest" import { type BundlerClient, ENTRYPOINT_ADDRESS_V07, type UserOperation, WaitForUserOperationReceiptTimeoutError, getUserOperationHash -} from "permissionless" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { type Chain, isHash } from "viem" -import { foundry } from "viem/chains" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts b/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts index cb5b693f..f4a0a7ba 100644 --- a/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/coreSmartClinetActions.test.ts @@ -1,17 +1,3 @@ -import { - type BundlerClient, - ENTRYPOINT_ADDRESS_V07, - createSmartAccountClient -} from "permissionless" -import { - SignTransactionNotSupportedBySmartAccount, - signerToEcdsaKernelSmartAccount, - signerToSafeSmartAccount, - signerToSimpleSmartAccount -} from "permissionless/accounts" -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { getUserOperationHash } from "permissionless/utils" import { http, type BaseError, @@ -29,6 +15,20 @@ import { import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { foundry } from "viem/chains" import { beforeAll, describe, expect, test } from "vitest" +import { + type BundlerClient, + ENTRYPOINT_ADDRESS_V07, + createSmartAccountClient +} from "../../../permissionless" +import { + SignTransactionNotSupportedBySmartAccount, + signerToEcdsaKernelSmartAccount, + signerToSafeSmartAccount, + signerToSimpleSmartAccount +} from "../../../permissionless/accounts" +import type { PimlicoPaymasterClient } from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" +import { getUserOperationHash } from "../../../permissionless/utils" import { ENTRYPOINT_V07_ABI } from "../../abi/entryPointV07Abi" import { SIMPLE_ACCOUNT_FACTORY_V07 } from "../constants" import type { AAParamType, ExistingSignerParamType } from "../types" diff --git a/packages/permissionless-test/src/ep-0.7/experiments.ts b/packages/permissionless-test/src/ep-0.7/experiments.ts index 6d04cc39..ae3e9a79 100644 --- a/packages/permissionless-test/src/ep-0.7/experiments.ts +++ b/packages/permissionless-test/src/ep-0.7/experiments.ts @@ -1,15 +1,15 @@ -import { - ENTRYPOINT_ADDRESS_V07, - createSmartAccountClient -} from "permissionless" -import { privateKeyToSimpleSmartAccount } from "permissionless/_types/accounts" -import { privateKeyToSafeSmartAccount } from "permissionless/accounts" -import { paymasterActionsEip7677 } from "permissionless/experimental" -import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types" import { http, createClient, zeroAddress } from "viem" import { generatePrivateKey } from "viem/accounts" import { foundry } from "viem/chains" import { describe, test } from "vitest" +import { + ENTRYPOINT_ADDRESS_V07, + createSmartAccountClient +} from "../../../permissionless" +import { privateKeyToSimpleSmartAccount } from "../../../permissionless/_types/accounts" +import { privateKeyToSafeSmartAccount } from "../../../permissionless/accounts" +import { paymasterActionsEip7677 } from "../../../permissionless/experimental" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../../permissionless/types" import { SIMPLE_ACCOUNT_FACTORY_V07 } from "../constants" import type { AAParamType } from "../types" import { diff --git a/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts b/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts index ea488f65..a7f815e8 100644 --- a/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts +++ b/packages/permissionless-test/src/ep-0.7/pimlicoActions.test.ts @@ -1,11 +1,11 @@ -import { ENTRYPOINT_ADDRESS_V07 } from "permissionless" +import { isAddress, isHash, zeroAddress } from "viem" +import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V07 } from "../../../permissionless" import type { PimlicoBundlerClient, PimlicoPaymasterClient -} from "permissionless/clients/pimlico" -import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "permissionless/types" -import { isAddress, isHash, zeroAddress } from "viem" -import { beforeAll, describe, expect, test } from "vitest" +} from "../../../permissionless/clients/pimlico" +import type { ENTRYPOINT_ADDRESS_V07_TYPE } from "../../../permissionless/types" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts b/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts index 098b5dfc..d09fc409 100644 --- a/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts +++ b/packages/permissionless-test/src/ep-0.7/safeSmartAccount.test.ts @@ -1,6 +1,6 @@ -import { ENTRYPOINT_ADDRESS_V07 } from "permissionless" import { isHash, zeroAddress } from "viem" import { beforeAll, describe, expect, test } from "vitest" +import { ENTRYPOINT_ADDRESS_V07 } from "../../../permissionless" import { ensureBundlerIsReady, ensurePaymasterIsReady, diff --git a/packages/permissionless-test/src/testWithRpc.ts b/packages/permissionless-test/src/testWithRpc.ts new file mode 100644 index 00000000..d05b837e --- /dev/null +++ b/packages/permissionless-test/src/testWithRpc.ts @@ -0,0 +1,109 @@ +import getPort from "get-port" +import { alto, anvil } from "prool/instances" +import { foundry } from "viem/chains" +import { test } from "vitest" +import type { EntryPoint } from "../../permissionless/types/entrypoint" +import { + ENTRYPOINT_ADDRESS_V06, + ENTRYPOINT_ADDRESS_V07 +} from "../../permissionless/utils" +import { + ENTRY_POINT_SIMULATIONS_ADDRESS, + setupContracts +} from "../mock-aa-infra/alto" +import { paymaster } from "../mock-aa-infra/mock-paymaster" + +export const getAltoInstance = async ({ + anvilPort, + altoPort, + paymasterPort +}: { anvilPort: number; altoPort: number; paymasterPort: number }) => { + const anvilRpc = `http://localhost:${anvilPort}` + const altoRpc = `http://localhost:${altoPort}` + + const anvilPrivateKey = + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + + const anvilInstance = anvil({ + chainId: foundry.id, + port: anvilPort + }) + + const instance = alto({ + entrypoints: [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07], + rpcUrl: anvilRpc, + executorPrivateKeys: [anvilPrivateKey], + entrypointSimulationContract: ENTRY_POINT_SIMULATIONS_ADDRESS, + safeMode: false, + port: altoPort + }) + + // instance.on("stderr", (data) => { + // console.error(data.toString()) + // }) + // instance.on("stdout", (data) => { + // console.log(data.toString()) + // }) + + const paymasterInstance = paymaster({ + anvilRpc, + port: paymasterPort, + altoRpc + }) + await anvilInstance.start() + await setupContracts(anvilRpc) + await instance.start() + await paymasterInstance.start() + + return [anvilInstance, instance, paymasterInstance] +} + +let ports: number[] = [] + +export const testWithRpc = test.extend<{ + rpc: { + anvilRpc: string + altoRpc: string + paymasterRpc: string + } +}>({ + // biome-ignore lint/correctness/noEmptyPattern: Needed in vitest :/ + rpc: async ({}, use) => { + const altoPort = await getPort({ + exclude: ports + }) + ports.push(altoPort) + const paymasterPort = await getPort({ + exclude: ports + }) + ports.push(paymasterPort) + const anvilPort = await getPort({ + exclude: ports + }) + ports.push(anvilPort) + + const anvilRpc = `http://localhost:${anvilPort}` + const altoRpc = `http://localhost:${altoPort}` + const paymasterRpc = `http://localhost:${paymasterPort}` + + const instances = await getAltoInstance({ + anvilPort, + altoPort, + paymasterPort + }) + + await use({ + anvilRpc, + altoRpc, + paymasterRpc + }) + + await Promise.all([...instances.map((instance) => instance.stop())]) + ports = ports.filter( + (port) => + port !== altoPort || + port !== anvilPort || + port !== paymasterPort + ) + } +}) diff --git a/packages/permissionless-test/src/types.ts b/packages/permissionless-test/src/types.ts index 80903a54..3cfd89a6 100644 --- a/packages/permissionless-test/src/types.ts +++ b/packages/permissionless-test/src/types.ts @@ -1,9 +1,11 @@ -import type { PimlicoPaymasterClient } from "permissionless/clients/pimlico" -import type { EntryPoint } from "permissionless/types" import type { Address, Hex, PublicClient } from "viem" +import type { PimlicoPaymasterClient } from "../../permissionless/clients/pimlico" +import type { EntryPoint } from "../../permissionless/types" export type AAParamType = { entryPoint: T + anvilRpc: string + altoRpc: string paymasterClient?: PimlicoPaymasterClient privateKey?: Hex } diff --git a/packages/permissionless-test/src/utils.ts b/packages/permissionless-test/src/utils.ts index 0649e07c..86d6ffd2 100644 --- a/packages/permissionless-test/src/utils.ts +++ b/packages/permissionless-test/src/utils.ts @@ -1,3 +1,22 @@ +import { + http, + type Account, + type Address, + type Chain, + type Hex, + type Transport, + type WalletClient, + createClient, + createPublicClient, + createWalletClient, + parseEther +} from "viem" +import { + generatePrivateKey, + mnemonicToAccount, + privateKeyToAccount +} from "viem/accounts" +import { foundry } from "viem/chains" import { type BundlerClient, ENTRYPOINT_ADDRESS_V06, @@ -5,7 +24,7 @@ import { createBundlerClient, createSmartAccountClient, getEntryPointVersion -} from "permissionless" +} from "../../permissionless" import { type SafeSmartAccount, type SmartAccount, @@ -15,50 +34,32 @@ import { signerToSafeSmartAccount, signerToSimpleSmartAccount, signerToTrustSmartAccount -} from "permissionless/accounts" -import type { KernelEcdsaSmartAccount } from "permissionless/accounts" +} from "../../permissionless/accounts" +import type { KernelEcdsaSmartAccount } from "../../permissionless/accounts" import { type PimlicoBundlerClient, type PimlicoPaymasterClient, createPimlicoBundlerClient, createPimlicoPaymasterClient -} from "permissionless/clients/pimlico" -import { paymasterActionsEip7677 } from "permissionless/experimental" +} from "../../permissionless/clients/pimlico" +import { paymasterActionsEip7677 } from "../../permissionless/experimental" import type { ENTRYPOINT_ADDRESS_V06_TYPE, EntryPoint -} from "permissionless/types" -import { - http, - type Account, - type Address, - type Chain, - type Hex, - type Transport, - type WalletClient, - createClient, - createPublicClient, - createWalletClient, - parseEther -} from "viem" -import { - generatePrivateKey, - mnemonicToAccount, - privateKeyToAccount -} from "viem/accounts" -import { foundry } from "viem/chains" +} from "../../permissionless/types" import { SIMPLE_ACCOUNT_FACTORY_V06, SIMPLE_ACCOUNT_FACTORY_V07 } from "./constants" -import type { AAParamType } from "./types" +import type { AAParamType, ExistingSignerParamType } from "./types" -export const ALTO_RPC = "http://localhost:4337" -const ANVIL_RPC = "http://localhost:8545" export const PAYMASTER_RPC = "http://localhost:3000" -export const ensureBundlerIsReady = async () => { - const bundlerClient = getBundlerClient(ENTRYPOINT_ADDRESS_V06) +export const ensureBundlerIsReady = async (altoRpc: string) => { + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: altoRpc + }) while (true) { try { @@ -86,7 +87,10 @@ export const ensurePaymasterIsReady = async () => { } } -export const getAnvilWalletClient = (addressIndex: number) => { +export const getAnvilWalletClient = ({ + addressIndex, + anvilRpc +}: { addressIndex: number; anvilRpc: string }) => { return createWalletClient({ account: mnemonicToAccount( "test test test test test test test test test test test junk", @@ -95,55 +99,62 @@ export const getAnvilWalletClient = (addressIndex: number) => { } ), chain: foundry, - transport: http(ANVIL_RPC) + transport: http(anvilRpc) }) } -export const getPimlicoPaymasterClient = ( - entryPoint: T -): PimlicoPaymasterClient => { +export const getPimlicoPaymasterClient = ({ + entryPoint, + paymasterRpc +}: { entryPoint: T; paymasterRpc: string }): PimlicoPaymasterClient => { return createPimlicoPaymasterClient({ chain: foundry, - transport: http(PAYMASTER_RPC), + transport: http(paymasterRpc), entryPoint }) } -export const getBundlerClient = ( - entryPoint: T -): BundlerClient => +export const getBundlerClient = ({ + entryPoint, + altoRpc +}: { entryPoint: T; altoRpc: string }): BundlerClient => createBundlerClient({ chain: foundry, entryPoint, - transport: http(ALTO_RPC) + transport: http(altoRpc) }) as BundlerClient -export const getPimlicoBundlerClient = ( - entryPoint: T -): PimlicoBundlerClient => +export const getPimlicoBundlerClient = ({ + entryPoint, + altoRpc +}: { entryPoint: T; altoRpc: string }): PimlicoBundlerClient => createPimlicoBundlerClient({ chain: foundry, entryPoint, - transport: http(ALTO_RPC) + transport: http(altoRpc) }) -export const getPublicClient = () => { +export const getPublicClient = (anvilRpc: string) => { return createPublicClient({ chain: foundry, - transport: http(ANVIL_RPC), + transport: http(anvilRpc), pollingInterval: 100 }) } -const publicClient = getPublicClient() -const wallets = Array.from({ length: 100 }, (_, index) => - getAnvilWalletClient(index) -) const usedWallets = new Set
() -export const fund = async (to: Address) => { +export const fund = async ({ + to, + anvilRpc +}: { to: Address; anvilRpc: string }) => { let funder: WalletClient + const wallets = Array.from({ length: 10 }, (_, index) => + getAnvilWalletClient({ addressIndex: index, anvilRpc }) + ) + const publicClient = getPublicClient(anvilRpc) + do { const availableFunders = wallets.filter( (wallet) => !usedWallets.has(wallet.account.address) @@ -183,10 +194,14 @@ export const getFactoryAddress = ( export const getSimpleAccountClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) + const smartAccount = await signerToSimpleSmartAccount( publicClient, { @@ -196,25 +211,29 @@ export const getSimpleAccountClient = async ({ } ) - // @ts-ignore return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), - middleware: { - // @ts-ignore - sponsorUserOperation: paymasterClient?.sponsorUserOperation - } + bundlerTransport: http(altoRpc), + // @ts-ignore + middleware: paymasterClient + ? { + sponsorUserOperation: paymasterClient.sponsorUserOperation + } + : undefined }) } export const getLightAccountClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const smartAccount = await signerToLightSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), @@ -224,7 +243,7 @@ export const getLightAccountClient = async ({ return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), entryPoint: entryPoint, // eip7677Client: await getEip7677Client({ entryPoint }), middleware: { @@ -235,13 +254,18 @@ export const getLightAccountClient = async ({ } // Only supports v0.6 for now -export const getTrustAccountClient = async ({ +export const getTrustAccountClient = async < + T extends ENTRYPOINT_ADDRESS_V06_TYPE +>({ entryPoint, paymasterClient, + altoRpc, + anvilRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const smartAccount = await signerToTrustSmartAccount( publicClient, { @@ -254,7 +278,7 @@ export const getTrustAccountClient = async ({ return createSmartAccountClient({ chain: foundry, account: smartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -266,8 +290,11 @@ export const getTrustAccountClient = async ({ export const getBiconomyClient = async ({ paymasterClient, privateKey = generatePrivateKey(), + anvilRpc, + altoRpc, entryPoint = ENTRYPOINT_ADDRESS_V06 }: AAParamType) => { + const publicClient = getPublicClient(anvilRpc) const ecdsaSmartAccount = await signerToBiconomySmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey) @@ -277,7 +304,7 @@ export const getBiconomyClient = async ({ return createSmartAccountClient({ account: ecdsaSmartAccount, chain: foundry, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -288,10 +315,13 @@ export const getBiconomyClient = async ({ export const getKernelEcdsaClient = async ({ entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: AAParamType): Promise< SmartAccountClient> > => { + const publicClient = getPublicClient(anvilRpc) const kernelEcdsaAccount = await signerToEcdsaKernelSmartAccount( publicClient, { @@ -304,7 +334,7 @@ export const getKernelEcdsaClient = async ({ return createSmartAccountClient({ chain: foundry, account: kernelEcdsaAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -316,6 +346,8 @@ export const getSafeClient = async ({ setupTransactions = [], entryPoint, paymasterClient, + anvilRpc, + altoRpc, privateKey = generatePrivateKey() }: { setupTransactions?: { @@ -323,10 +355,13 @@ export const getSafeClient = async ({ data: Address value: bigint }[] + anvilRpc: string + altoRpc: string entryPoint: T paymasterClient?: PimlicoPaymasterClient privateKey?: Hex }): Promise>> => { + const publicClient = getPublicClient(anvilRpc) const safeSmartAccount = await signerToSafeSmartAccount(publicClient, { entryPoint, signer: privateKeyToAccount(privateKey), @@ -339,7 +374,7 @@ export const getSafeClient = async ({ return createSmartAccountClient({ chain: foundry, account: safeSmartAccount, - bundlerTransport: http(ALTO_RPC), + bundlerTransport: http(altoRpc), middleware: { // @ts-ignore sponsorUserOperation: paymasterClient?.sponsorUserOperation @@ -357,3 +392,112 @@ export const getEip7677Client = async ({ return client } + +export const getCoreSmartAccounts = () => [ + { + name: "Trust", + getSmartAccountClient: async ( + conf: AAParamType + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getTrustAccountClient( + conf as AAParamType + ) + }, + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToTrustSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: false, + isEip1271Compliant: true + }, + { + name: "LightAccount v1.1.0", + getSmartAccountClient: async ( + conf: AAParamType + ) => getLightAccountClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToLightSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06, + lightAccountVersion: "1.1.0" + }), + supportsEntryPointV06: true, + supportsEntryPointV07: false, + isEip1271Compliant: true + }, + { + name: "Simple", + getSmartAccountClient: async ( + conf: AAParamType + ) => getSimpleAccountClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToSimpleSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: false + }, + { + name: "Kernel", + getSmartAccountClient: async ( + conf: AAParamType + ) => getKernelEcdsaClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToEcdsaKernelSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + }, + { + name: "Biconomy", + getSmartAccountClient: async ( + conf: AAParamType + ) => { + if (conf.entryPoint !== ENTRYPOINT_ADDRESS_V06) { + throw new Error("Biconomy only works with V06") + } + return getBiconomyClient( + conf as AAParamType + ) + }, + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToBiconomySmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }), + supportsEntryPointV06: true, + supportsEntryPointV07: false, + isEip1271Compliant: true + }, + { + name: "Safe", + getSmartAccountClient: async ( + conf: AAParamType + ) => getSafeClient(conf), + getSmartAccountSigner: async (conf: ExistingSignerParamType) => + signerToSafeSmartAccount(conf.publicClient, { + address: conf.existingAddress, // this is the field we are testing + signer: privateKeyToAccount(conf.privateKey), + entryPoint: ENTRYPOINT_ADDRESS_V06, + safeVersion: "1.4.1" + }), + supportsEntryPointV06: true, + supportsEntryPointV07: true, + isEip1271Compliant: true + } +] diff --git a/packages/permissionless-test/tsconfig.json b/packages/permissionless-test/tsconfig.json deleted file mode 100644 index 33f68e91..00000000 --- a/packages/permissionless-test/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "CommonJS", - "strict": true, - "allowJs": true, - "moduleResolution": "node", - "skipLibCheck": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, - "suppressImplicitAnyIndexErrors": true, - "declaration": false - } -} diff --git a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts index bf8b2e3c..4d0795e5 100644 --- a/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts +++ b/packages/permissionless/accounts/kernel/signerToEcdsaKernelSmartAccount.ts @@ -14,9 +14,9 @@ import { zeroAddress } from "viem" import { + signMessage as _signMessage, getChainId, - readContract, - signMessage as _signMessage + readContract } from "viem/actions" import { getAccountNonce } from "../../actions/public/getAccountNonce" import { getSenderAddress } from "../../actions/public/getSenderAddress" diff --git a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts index ab638f68..f3cfe41d 100644 --- a/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts +++ b/packages/permissionless/accounts/trust/privateKeyToTrustSmartAccount.ts @@ -1,4 +1,4 @@ -import { type Chain, type Client, type Hex, type Transport } from "viem" +import type { Chain, Client, Hex, Transport } from "viem" import { privateKeyToAccount } from "viem/accounts" import type { ENTRYPOINT_ADDRESS_V06_TYPE, Prettify } from "../../types" import { diff --git a/packages/permissionless/accounts/trust/utils/signUserOperation.ts b/packages/permissionless/accounts/trust/utils/signUserOperation.ts index d499426f..0ff0393a 100644 --- a/packages/permissionless/accounts/trust/utils/signUserOperation.ts +++ b/packages/permissionless/accounts/trust/utils/signUserOperation.ts @@ -1,10 +1,10 @@ -import { getUserOperationHash } from "permissionless/utils" import type { Account, Address, Chain, Client, Transport } from "viem" import type { EntryPoint, GetEntryPointVersion, UserOperation } from "../../../types" +import { getUserOperationHash } from "../../../utils" import { signMessage } from "./signMessage" export const signUserOperation = async < diff --git a/packages/permissionless/actions/bundler/chainId.test.ts b/packages/permissionless/actions/bundler/chainId.test.ts new file mode 100644 index 00000000..8d5ecf5e --- /dev/null +++ b/packages/permissionless/actions/bundler/chainId.test.ts @@ -0,0 +1,25 @@ +import { http } from "viem" +import { foundry } from "viem/chains" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + type BundlerClient, + createBundlerClient +} from "../../clients/createBundlerClient" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { chainId } from "./chainId" + +describe("chainId", () => { + testWithRpc("chainId", async ({ rpc }) => { + const { altoRpc } = rpc + const entryPoint = ENTRYPOINT_ADDRESS_V06 + + const bundlerClient = createBundlerClient({ + transport: http(altoRpc), + entryPoint + }) + const id = await chainId(bundlerClient) + expect(id).toBe(foundry.id) + }) +}) diff --git a/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts new file mode 100644 index 00000000..9329a493 --- /dev/null +++ b/packages/permissionless/actions/bundler/estimateUserOperationGas.test.ts @@ -0,0 +1,205 @@ +import { http, parseEther } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { estimateUserOperationGas } from "./estimateUserOperationGas" + +describe("eth_estimateUserOperationGas", () => { + testWithRpc("eth_estimateUserOperationGas_v06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { preVerificationGas, verificationGasLimit, callGasLimit } = + await estimateUserOperationGas( + bundlerClientV06, + { + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V06 + }, + { + "0xa5cc3c03994DB5b0d9A5eEdD10CabaB0813678AC": { + balance: parseEther("1"), + stateDiff: { + "0x3ea2f1d0abf3fc66cf29eebb70cbd4e7fe762ef8a09bcc06c8edf641230afec0": + "0x00000000000000000000000000000000000000000000000000000000000001a4" + } + } + } + ) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + }) + + testWithRpc("eth_estimateUserOperationGas_v07", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { + preVerificationGas, + verificationGasLimit, + callGasLimit, + paymasterVerificationGasLimit, + paymasterPostOpGasLimit + } = await estimateUserOperationGas(bundlerClientV07, { + entryPoint: ENTRYPOINT_ADDRESS_V07, + userOperation + }) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + expect(paymasterVerificationGasLimit).toBe(0n) + expect(paymasterPostOpGasLimit).toBe(0n) + }) + + testWithRpc( + "eth_estimateUserOperationGas_V07_with_error", + async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 1000n + }) + } + }) + + await expect(() => + estimateUserOperationGas( + bundlerClientV07, + { + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }, + { + [smartAccountClient.account.address]: { + balance: 0n + } + } + ) + ).rejects.toThrowError(/AA21/) + } + ) + + testWithRpc( + "eth_estimateUserOperationGas_V07_withPaymaster", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const smartAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await smartAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: + await smartAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const { + preVerificationGas, + verificationGasLimit, + callGasLimit, + paymasterVerificationGasLimit, + paymasterPostOpGasLimit + } = await estimateUserOperationGas(bundlerClientV07, { + userOperation, + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + expect(preVerificationGas).toBeTruthy() + expect(verificationGasLimit).toBeTruthy() + expect(callGasLimit).toBeTruthy() + expect(paymasterVerificationGasLimit).toBeTruthy() + expect(paymasterPostOpGasLimit).toBeTruthy() + } + ) +}) diff --git a/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts new file mode 100644 index 00000000..f9693cd5 --- /dev/null +++ b/packages/permissionless/actions/bundler/getUserOperationByHash.test.ts @@ -0,0 +1,139 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationByHash } from "./getUserOperationByHash" + +describe("getUserOperationByHash", () => { + testWithRpc("getUserOperationByHash_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + const bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 10000 + }) + + const userOperationFromUserOpHash = await getUserOperationByHash( + bundlerClientV06, + { hash: opHash } + ) + + expect(userOperationFromUserOpHash).not.toBeNull() + expect(userOperationFromUserOpHash?.entryPoint).toBe( + ENTRYPOINT_ADDRESS_V06 + ) + + for (const key in userOperationFromUserOpHash?.userOperation) { + const expected = userOperationFromUserOpHash?.userOperation[key] + const actual = userOperation[key] + + if (typeof expected === "string" && typeof actual === "string") { + expect(expected.toLowerCase()).toBe(actual.toLowerCase()) + } else { + expect(expected).toBe(actual) + } + } + }) + + testWithRpc("getUserOperationByHash_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 10000 + }) + + const userOperationFromUserOpHash = await getUserOperationByHash( + bundlerClientV07, + { hash: opHash } + ) + + for (const key in userOperationFromUserOpHash?.userOperation) { + const expected = userOperationFromUserOpHash?.userOperation[key] + const actual = userOperation[key] + + if (typeof expected === "string" && typeof actual === "string") { + expect(expected.toLowerCase()).toBe(actual.toLowerCase()) + } else { + expect(expected).toBe(actual) + } + } + }) +}) diff --git a/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts new file mode 100644 index 00000000..e7693263 --- /dev/null +++ b/packages/permissionless/actions/bundler/getUserOperationReceipt.test.ts @@ -0,0 +1,127 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationReceipt } from "./getUserOperationReceipt" + +describe("getUserOperationReceipt", () => { + testWithRpc("getUserOperationReceipt_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await getUserOperationReceipt(bundlerClientV06, { + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("getUserOperationReceipt_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await getUserOperationReceipt(bundlerClientV07, { + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/bundler/sendUserOperation.test.ts b/packages/permissionless/actions/bundler/sendUserOperation.test.ts new file mode 100644 index 00000000..e1085f95 --- /dev/null +++ b/packages/permissionless/actions/bundler/sendUserOperation.test.ts @@ -0,0 +1,126 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationReceipt } from "./getUserOperationReceipt" + +describe("sendUserOperation", () => { + testWithRpc("sendUserOperation_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await getUserOperationReceipt(bundlerClientV06, { + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("sendUserOperation_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await getUserOperationReceipt(bundlerClientV07, { + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts new file mode 100644 index 00000000..dca58f4d --- /dev/null +++ b/packages/permissionless/actions/bundler/supportedEntryPoints.test.ts @@ -0,0 +1,27 @@ +import { http } from "viem" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { supportedEntryPoints } from "./supportedEntryPoints" + +describe("supportedEntryPoints", () => { + testWithRpc("supportedEntryPoints_V06", async ({ rpc }) => { + const bundlerClientV06 = createBundlerClient({ + transport: http(rpc.altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + + const entryPoints = await supportedEntryPoints(bundlerClientV06) + expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V06) + }) + + testWithRpc("supportedEntryPoints_V07", async ({ rpc }) => { + const bundlerClientV07 = createBundlerClient({ + transport: http(rpc.altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + const entryPoints = await supportedEntryPoints(bundlerClientV07) + expect(entryPoints).contain(ENTRYPOINT_ADDRESS_V07) + }) +}) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts new file mode 100644 index 00000000..df30228b --- /dev/null +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.test.ts @@ -0,0 +1,130 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { waitForUserOperationReceipt } from "./waitForUserOperationReceipt" + +describe("waitForUserOperationReceipt", () => { + testWithRpc("waitForUserOperationReceipt_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V06 + }) + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = await waitForUserOperationReceipt( + bundlerClientV06, + { + hash: opHash, + timeout: 100000 + } + ) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("waitForUserOperationReceipt_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + transport: http(altoRpc), + entryPoint: ENTRYPOINT_ADDRESS_V07 + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = await waitForUserOperationReceipt( + bundlerClientV07, + { + hash: opHash, + timeout: 100000 + } + ) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts index 676edd0a..8ed2a875 100644 --- a/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts +++ b/packages/permissionless/actions/bundler/waitForUserOperationReceipt.ts @@ -19,7 +19,7 @@ export class WaitForUserOperationReceiptTimeoutError extends BaseError { override name = "WaitForUserOperationReceiptTimeoutError" constructor({ hash }: { hash: Hash }) { super( - `Timed out while waiting for transaction with hash "${hash}" to be confirmed.` + `Timed out while waiting for user operation with hash "${hash}" to be confirmed.` ) } } diff --git a/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts new file mode 100644 index 00000000..492c353b --- /dev/null +++ b/packages/permissionless/actions/pimlico/getUserOperationGasPrice.test.ts @@ -0,0 +1,33 @@ +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getPimlicoBundlerClient } from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { getUserOperationGasPrice } from "./getUserOperationGasPrice" + +describe("getUserOperationGasPrice", () => { + testWithRpc("getUserOperationGasPrice", async ({ rpc }) => { + const pimlicoBundlerClient = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: rpc.altoRpc + }) + + const gasPrice = await getUserOperationGasPrice(pimlicoBundlerClient) + + expect(gasPrice).toBeTruthy() + expect(gasPrice.slow).toBeTruthy() + expect(gasPrice.standard).toBeTruthy() + expect(gasPrice.fast).toBeTruthy() + expect(typeof gasPrice.slow.maxFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.slow.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.slow.maxPriorityFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.standard.maxFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.standard.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.standard.maxPriorityFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.fast.maxFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxFeePerGas).toBeGreaterThan(0n) + expect(typeof gasPrice.fast.maxPriorityFeePerGas).toBe("bigint") + expect(gasPrice.fast.maxPriorityFeePerGas).toBeGreaterThan(0n) + }) +}) diff --git a/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts new file mode 100644 index 00000000..60c4521d --- /dev/null +++ b/packages/permissionless/actions/pimlico/getUserOperationStatus.test.ts @@ -0,0 +1,152 @@ +import { isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoBundlerClient, + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { bundlerActions } from "../../clients/decorators/bundler" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getUserOperationStatus } from "./getUserOperationStatus" + +describe("getUserOperationStatus", () => { + testWithRpc("getUserOperationStatus_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc: altoRpc + }).extend(bundlerActions(ENTRYPOINT_ADDRESS_V06)) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + const userOperationStatus = await getUserOperationStatus( + bundlerClientV06, + { + hash: opHash + } + ) + expect(userOperationStatus).not.toBeNull() + expect(userOperationStatus).not.toBeUndefined() + expect(userOperationStatus.status).toBe("included") + expect(userOperationStatus.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("getUserOperationStatus_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = getPimlicoBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + altoRpc: altoRpc + }).extend(bundlerActions(ENTRYPOINT_ADDRESS_V07)) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + const userOperationStatus = await getUserOperationStatus( + bundlerClientV07, + { + hash: opHash + } + ) + expect(userOperationStatus).not.toBeNull() + expect(userOperationStatus).not.toBeUndefined() + expect(userOperationStatus.status).toBe("included") + expect(userOperationStatus.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts b/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts new file mode 100644 index 00000000..1a1d4d2d --- /dev/null +++ b/packages/permissionless/actions/pimlico/sponsorUserOperation.test.ts @@ -0,0 +1,126 @@ +import { http, isHash, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { createBundlerClient } from "../../clients/createBundlerClient" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" + +describe("sponsorUserOperation", () => { + testWithRpc("sponsorUserOperation_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV06 = createBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + transport: http(altoRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV06.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV06.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV06.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) + + testWithRpc("sponsorUserOperation_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const bundlerClientV07 = createBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + transport: http(altoRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + }) + + userOperation.signature = + await simpleAccountClient.account.signUserOperation(userOperation) + + const opHash = await bundlerClientV07.sendUserOperation({ + userOperation + }) + + expect(isHash(opHash)).toBe(true) + + const userOperationReceipt = + await bundlerClientV07.waitForUserOperationReceipt({ + hash: opHash, + timeout: 100000 + }) + expect(userOperationReceipt).not.toBeNull() + expect(userOperationReceipt?.userOpHash).toBe(opHash) + expect(userOperationReceipt?.receipt.transactionHash).toBeTruthy() + + const receipt = await bundlerClientV07.getUserOperationReceipt({ + hash: opHash + }) + + expect(receipt?.receipt.transactionHash).toBe( + userOperationReceipt?.receipt.transactionHash + ) + }) +}) diff --git a/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts new file mode 100644 index 00000000..9f836468 --- /dev/null +++ b/packages/permissionless/actions/pimlico/validateSponsorshipPolicies.test.ts @@ -0,0 +1,56 @@ +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getPimlicoPaymasterClient, + getSimpleAccountClient +} from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06 } from "../../utils" +import { validateSponsorshipPolicies } from "./validateSponsorshipPolicies" + +describe("validateSponsorshipPolicies", () => { + testWithRpc("Validating sponsorship policies", async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperation = + await simpleAccountClient.prepareUserOperationRequest({ + userOperation: { + callData: await simpleAccountClient.account.encodeCallData({ + to: "0x5af0d9827e0c53e4799bb226655a1de152a425a5", + data: "0x", + value: 0n + }) + } + }) + + const pimlicoPaymasterClient = getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + + const policies = await validateSponsorshipPolicies( + pimlicoPaymasterClient, + { + entryPoint: ENTRYPOINT_ADDRESS_V06, + userOperation: userOperation, + sponsorshipPolicyIds: ["sp_crazy_kangaroo"] + } + ) + + expect(policies).toBeTruthy() + expect(policies.length).toBeGreaterThan(0) + expect(Array.isArray(policies)).toBe(true) + expect(policies.length).toBe(1) + }) +}) diff --git a/packages/permissionless/actions/public/getAccountNonce.test.ts b/packages/permissionless/actions/public/getAccountNonce.test.ts new file mode 100644 index 00000000..2fe9099e --- /dev/null +++ b/packages/permissionless/actions/public/getAccountNonce.test.ts @@ -0,0 +1,52 @@ +import { http, createPublicClient } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getSimpleAccountClient } from "../../../permissionless-test/src/utils" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getAccountNonce } from "./getAccountNonce" + +describe("getAccountNonce", () => { + testWithRpc("getAccountNonce_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const nonce = await getAccountNonce(client, { + entryPoint: ENTRYPOINT_ADDRESS_V06, + sender: simpleAccountClient.account.address + }) + + expect(nonce).toBe(0n) + }) + testWithRpc("getAccountNonce_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const nonce = await getAccountNonce(client, { + entryPoint: ENTRYPOINT_ADDRESS_V07, + sender: simpleAccountClient.account.address + }) + + expect(nonce).toBe(0n) + }) +}) diff --git a/packages/permissionless/actions/public/getSenderAddress.test.ts b/packages/permissionless/actions/public/getSenderAddress.test.ts new file mode 100644 index 00000000..dc8680de --- /dev/null +++ b/packages/permissionless/actions/public/getSenderAddress.test.ts @@ -0,0 +1,83 @@ +import { http, createPublicClient } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getSimpleAccountClient } from "../../../permissionless-test/src/utils" +import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "../../_types/types" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { getSenderAddress } from "./getSenderAddress" + +describe("getSenderAddress", () => { + testWithRpc("getSenderAddress_V06", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const address = await getSenderAddress(client, { + entryPoint: ENTRYPOINT_ADDRESS_V06, + initCode: await simpleAccountClient.account.getInitCode() + }) + + expect(address).toBe(simpleAccountClient.account.address) + }) + testWithRpc("getSenderAddress_V06_error", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + await expect(async () => + getSenderAddress(client, { + entryPoint: + "0x0000000000000000000000000000000000000000" as ENTRYPOINT_ADDRESS_V06_TYPE, + initCode: await simpleAccountClient.account.getInitCode() + }) + ).rejects.toThrowError(/not a valid entry point/) + }) + testWithRpc("getSenderAddress_V07", async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const client = createPublicClient({ + transport: http(anvilRpc) + }) + + const simpleAccountClient = await getSimpleAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const factory = await simpleAccountClient.account.getFactory() + const factoryData = await simpleAccountClient.account.getFactoryData() + + if (!factory || !factoryData) { + throw new Error("Factory or factoryData not found") + } + + const address = await getSenderAddress(client, { + entryPoint: ENTRYPOINT_ADDRESS_V07, + factory, + factoryData + }) + + expect(address).toBe(simpleAccountClient.account.address) + }) +}) diff --git a/packages/permissionless/actions/smartAccount/deployContract.test.ts b/packages/permissionless/actions/smartAccount/deployContract.test.ts new file mode 100644 index 00000000..c74b96c1 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/deployContract.test.ts @@ -0,0 +1,118 @@ +import type { Chain, Client, Transport } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { foundry } from "viem/chains" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import type { + ENTRYPOINT_ADDRESS_V06_TYPE, + ENTRYPOINT_ADDRESS_V07_TYPE, + EntryPoint +} from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { deployContract } from "./deployContract" + +describe.each(getCoreSmartAccounts())( + "deployContract $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "deployContract_V06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + await expect(async () => + deployContract( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + account: smartClient.account, + chain: foundry, + abi: [ + { + inputs: [], + stateMutability: "payable", + type: "constructor" + } + ], + bytecode: + "0x608060405260358060116000396000f3006080604052600080fd00a165627a7a72305820f86ff341f0dff29df244305f8aa88abaf10e3a0719fa6ea1dcdd01b8b7d750970029" + } + ) + ).rejects.toThrowError( + /^.*doesn't support account deployment.*$/i + ) + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "deployContract_V07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = (await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + })) as SmartAccountClient< + ENTRYPOINT_ADDRESS_V07_TYPE, + Transport, + Chain, + SmartAccount + > + + await expect(async () => + deployContract( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + account: smartClient.account, + chain: foundry, + abi: [ + { + inputs: [], + stateMutability: "payable", + type: "constructor" + } + ], + bytecode: + "0x608060405260358060116000396000f3006080604052600080fd00a165627a7a72305820f86ff341f0dff29df244305f8aa88abaf10e3a0719fa6ea1dcdd01b8b7d750970029" + } + ) + ).rejects.toThrowError( + /^.*doesn't support account deployment.*$/i + ) + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/deployContract.ts b/packages/permissionless/actions/smartAccount/deployContract.ts index 3782fc9d..99efd92e 100644 --- a/packages/permissionless/actions/smartAccount/deployContract.ts +++ b/packages/permissionless/actions/smartAccount/deployContract.ts @@ -59,7 +59,9 @@ export type DeployContractParametersWithPaymaster< export async function deployContract< entryPoint extends EntryPoint, TChain extends Chain | undefined, - TAccount extends SmartAccount | undefined + TAccount extends SmartAccount | undefined = + | SmartAccount + | undefined >( client: Client, args: Prettify> diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts new file mode 100644 index 00000000..f1755183 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.test.ts @@ -0,0 +1,151 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { getCoreSmartAccounts } from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { SmartAccountClient } from "../../clients/createSmartAccountClient" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { prepareUserOperationRequest } from "./prepareUserOperationRequest" + +describe.each(getCoreSmartAccounts())( + "prepareUserOperationRequest $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "prepareUserOperationRequest_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = await prepareUserOperationRequest( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + expect(userOperation).toBeTruthy() + expect(userOperation.sender).toBe(smartClient.account.address) + expect(userOperation.nonce).toBe( + await smartClient.account.getNonce() + ) + expect(userOperation.initCode).toBe( + await smartClient.account.getInitCode() + ) + expect(userOperation.callData).toBe( + await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + ) + expect(userOperation.callGasLimit).toBeTruthy() + expect(userOperation.verificationGasLimit).toBeTruthy() + expect(userOperation.maxFeePerGas).toBeTruthy() + expect(userOperation.maxPriorityFeePerGas).toBeTruthy() + expect(userOperation.paymasterAndData).toBe("0x") + expect(userOperation.signature).toBe( + // @ts-ignore: since tests return all smart account client, some of them don't support V06. + // The TS error is because in that case, getDummySignature would not accept the userOperation of type UserOperation + await smartClient.account.getDummySignature(userOperation) + ) + + expect(userOperation.factory).toBe(undefined) + expect(userOperation.factoryData).toBe(undefined) + expect(userOperation.paymaster).toBe(undefined) + expect(userOperation.paymasterVerificationGasLimit).toBe( + undefined + ) + expect(userOperation.paymasterPostOpGasLimit).toBe(undefined) + expect(userOperation.paymasterData).toBe(undefined) + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "prepareUserOperationRequest_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc + }) + + const userOperation = await prepareUserOperationRequest( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + + expect(userOperation).toBeTruthy() + expect(userOperation.sender).toBe(smartClient.account.address) + expect(userOperation.nonce).toBe( + await smartClient.account.getNonce() + ) + expect(userOperation.factory).toBe( + await smartClient.account.getFactory() + ) + expect(userOperation.factoryData).toBe( + await smartClient.account.getFactoryData() + ) + expect(userOperation.callData).toBe( + await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + ) + expect(userOperation.callGasLimit).toBeTruthy() + expect(userOperation.verificationGasLimit).toBeTruthy() + expect(userOperation.maxFeePerGas).toBeTruthy() + expect(userOperation.maxPriorityFeePerGas).toBeTruthy() + expect(userOperation.paymaster).toBe(undefined) + expect(userOperation.paymasterVerificationGasLimit).toBe( + undefined + ) + expect(userOperation.signature).toBe( + // @ts-ignore: since tests return all smart account client, some of them don't support V07. + // The TS error is because in that case, getDummySignature would not accept the userOperation of type UserOperation + await smartClient.account.getDummySignature(userOperation) + ) + expect(userOperation.paymasterPostOpGasLimit).toBe(0n) + expect(userOperation.paymasterData).toBe(undefined) + expect(userOperation.paymasterAndData).toBe(undefined) + expect(userOperation.initCode).toBe(undefined) + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts index 3220b266..16e9b20b 100644 --- a/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts +++ b/packages/permissionless/actions/smartAccount/prepareUserOperationRequest.ts @@ -387,10 +387,6 @@ async function prepareUserOperationRequestEntryPointV07< gasParameters.verificationGasLimit userOperation.preVerificationGas = userOperation.preVerificationGas || gasParameters.preVerificationGas - - userOperation.paymasterPostOpGasLimit = - userOperation.paymasterPostOpGasLimit || - gasParameters.paymasterPostOpGasLimit userOperation.paymasterPostOpGasLimit = userOperation.paymasterPostOpGasLimit || gasParameters.paymasterPostOpGasLimit diff --git a/packages/permissionless/actions/smartAccount/sendTransaction.test.ts b/packages/permissionless/actions/smartAccount/sendTransaction.test.ts new file mode 100644 index 00000000..35f5c1fa --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendTransaction.test.ts @@ -0,0 +1,108 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendTransaction } from "./sendTransaction" + +describe.each(getCoreSmartAccounts())( + "sendTransaction $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendTransaction_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const transactionHash = await sendTransaction( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendTransaction_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const transactionHash = await sendTransaction( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/sendTransactions.test.ts b/packages/permissionless/actions/smartAccount/sendTransactions.test.ts new file mode 100644 index 00000000..ef70b4b2 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendTransactions.test.ts @@ -0,0 +1,126 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendTransactions } from "./sendTransactions" + +describe.each(getCoreSmartAccounts())( + "sendTransactions $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendTransactions_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const transactionHash = await sendTransactions( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + transactions: [ + { + to: zeroAddress, + data: "0x", + value: 0n + }, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ] + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendTransactions_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const transactionHash = await sendTransactions( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + transactions: [ + { + to: zeroAddress, + data: "0x", + value: 0n + }, + { + to: zeroAddress, + data: "0x", + value: 0n + } + ] + } + ) + + expect(transactionHash).toBeTruthy() + + const publicClient = getPublicClient(anvilRpc) + + const receipt = await publicClient.getTransactionReceipt({ + hash: transactionHash + }) + + expect(receipt).toBeTruthy() + expect(receipt.transactionHash).toBe(transactionHash) + expect(receipt.status).toBe("success") + } + ) + } +) diff --git a/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts b/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts new file mode 100644 index 00000000..a5b28858 --- /dev/null +++ b/packages/permissionless/actions/smartAccount/sendUserOperation.test.ts @@ -0,0 +1,133 @@ +import { type Chain, type Client, type Transport, zeroAddress } from "viem" +import { generatePrivateKey } from "viem/accounts" +import { describe, expect } from "vitest" +import { testWithRpc } from "../../../permissionless-test/src/testWithRpc" +import { + getBundlerClient, + getCoreSmartAccounts, + getPimlicoPaymasterClient, + getPublicClient +} from "../../../permissionless-test/src/utils" +import type { SmartAccount } from "../../accounts" +import type { EntryPoint } from "../../types/entrypoint" +import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from "../../utils" +import { sendUserOperation } from "./sendUserOperation" + +describe.each(getCoreSmartAccounts())( + "sendUserOperation $name", + ({ + getSmartAccountClient, + supportsEntryPointV06, + supportsEntryPointV07 + }) => { + testWithRpc.skipIf(!supportsEntryPointV06)( + "sendUserOperation_v06", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + paymasterRpc + }) + }) + + const userOperationHash = await sendUserOperation( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + + expect(userOperationHash).toBeTruthy() + + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V06, + altoRpc + }) + + const receipt = await bundlerClient.waitForUserOperationReceipt( + { + hash: userOperationHash + } + ) + + expect(receipt).toBeTruthy() + expect(receipt.userOpHash).toBe(userOperationHash) + expect(receipt.entryPoint.toLowerCase()).toBe( + ENTRYPOINT_ADDRESS_V06.toLowerCase() + ) + expect(receipt.receipt.status).toBe("success") + } + ) + + testWithRpc.skipIf(!supportsEntryPointV07)( + "sendUserOperation_v07", + async ({ rpc }) => { + const { anvilRpc, altoRpc, paymasterRpc } = rpc + + const smartClient = await getSmartAccountClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + privateKey: generatePrivateKey(), + altoRpc: altoRpc, + anvilRpc: anvilRpc, + paymasterClient: getPimlicoPaymasterClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + paymasterRpc + }) + }) + + const userOperationHash = await sendUserOperation( + smartClient as Client< + Transport, + Chain, + SmartAccount + >, + { + userOperation: { + callData: await smartClient.account.encodeCallData({ + to: zeroAddress, + data: "0x", + value: 0n + }) + } + } + ) + + expect(userOperationHash).toBeTruthy() + + const bundlerClient = getBundlerClient({ + entryPoint: ENTRYPOINT_ADDRESS_V07, + altoRpc + }) + + const receipt = await bundlerClient.waitForUserOperationReceipt( + { + hash: userOperationHash + } + ) + + expect(receipt).toBeTruthy() + expect(receipt.userOpHash).toBe(userOperationHash) + expect(receipt.entryPoint.toLowerCase()).toBe( + ENTRYPOINT_ADDRESS_V07.toLowerCase() + ) + expect(receipt.receipt.status).toBe("success") + } + ) + } +) diff --git a/packages/permissionless/errors/estimateUserOperationGas.ts b/packages/permissionless/errors/estimateUserOperationGas.ts index 1e3f0691..4564692b 100644 --- a/packages/permissionless/errors/estimateUserOperationGas.ts +++ b/packages/permissionless/errors/estimateUserOperationGas.ts @@ -36,6 +36,13 @@ export class EstimateUserOperationGasError< maxPriorityFeePerGas: userOperation.maxPriorityFeePerGas, paymasterAndData: userOperation.paymasterAndData, signature: userOperation.signature, + factory: userOperation.factory, + factoryData: userOperation.factoryData, + paymaster: userOperation.paymaster, + paymasterVerificationGasLimit: + userOperation.paymasterVerificationGasLimit, + paymasterPostOpGasLimit: userOperation.paymasterPostOpGasLimit, + paymasterData: userOperation.paymasterData, entryPoint }) diff --git a/packages/permissionless/package.json b/packages/permissionless/package.json index e5a62fe2..a52850e7 100644 --- a/packages/permissionless/package.json +++ b/packages/permissionless/package.json @@ -11,13 +11,7 @@ "type": "module", "sideEffects": false, "description": "A utility library for working with ERC-4337", - "keywords": [ - "ethereum", - "erc-4337", - "eip-4337", - "paymaster", - "bundler" - ], + "keywords": ["ethereum", "erc-4337", "eip-4337", "paymaster", "bundler"], "license": "MIT", "exports": { ".": { diff --git a/packages/permissionless-test/vitest.config.ts b/packages/permissionless/vitest.config.ts similarity index 58% rename from packages/permissionless-test/vitest.config.ts rename to packages/permissionless/vitest.config.ts index 9b600d04..0361eae6 100644 --- a/packages/permissionless-test/vitest.config.ts +++ b/packages/permissionless/vitest.config.ts @@ -1,26 +1,32 @@ +import { join } from "node:path" import { defineConfig } from "vitest/config" export default defineConfig({ test: { + alias: { + permissionless: join(__dirname, "./") + }, coverage: { - all: false, + all: true, provider: "v8", reporter: process.env.CI ? ["lcov"] : ["text", "json", "html"], + include: ["**/permissionless/**"], exclude: [ "**/errors/utils.ts", + "**/*.test.ts", + "**/permissionless-test/**", "**/_cjs/**", "**/_esm/**", "**/_types/**" ] }, sequence: { - concurrent: true + concurrent: false }, fileParallelism: true, environment: "node", testTimeout: 60_000, - hookTimeout: 45_000 - // setupFiles: [join(__dirname, "./setup.ts")], - // globalSetup: [join(__dirname, "./globalSetup.ts")] + hookTimeout: 45_000, + include: [join(__dirname, "./**/*.test.ts")] } }) diff --git a/tsconfig/tsconfig.base.json b/tsconfig/tsconfig.base.json index a8ddd689..fc47f3bc 100644 --- a/tsconfig/tsconfig.base.json +++ b/tsconfig/tsconfig.base.json @@ -1,6 +1,5 @@ { // This tsconfig file contains the shared config for the build (tsconfig.build.json) and type checking (tsconfig.json) config. - "include": [], "compilerOptions": { // Incremental builds // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. @@ -42,4 +41,4 @@ "resolveFullPaths": true, "verbose": false } -} +} \ No newline at end of file diff --git a/tsconfig/tsconfig.permissionless.json b/tsconfig/tsconfig.permissionless.json index 632d24f9..cec9d51d 100644 --- a/tsconfig/tsconfig.permissionless.json +++ b/tsconfig/tsconfig.permissionless.json @@ -5,6 +5,8 @@ "../packages/permissionless" ], "exclude": [ + "../packages/permissionless-test/*", + "../packages/permissionless/**/setupTests.ts", "../packages/permissionless/**/*.test.ts", "../packages/permissionless/**/*.test-d.ts", "../packages/permissionless/**/*.bench.ts" @@ -14,4 +16,4 @@ "sourceMap": true, "rootDir": "../packages/permissionless" } -} +} \ No newline at end of file diff --git a/tsconfig/tsconfig.wagmi.json b/tsconfig/tsconfig.wagmi.json index 4770e5a4..20c976ab 100644 --- a/tsconfig/tsconfig.wagmi.json +++ b/tsconfig/tsconfig.wagmi.json @@ -5,6 +5,7 @@ "../packages/wagmi" ], "exclude": [ + "../packages/wagmi/node_modules", "../packages/wagmi/**/*.test.ts", "../packages/wagmi/**/*.test-d.ts", "../packages/wagmi/**/*.bench.ts" @@ -15,4 +16,4 @@ "rootDir": "../packages/wagmi" }, "jsx": "react-jsx", -} +} \ No newline at end of file