From c2b7f016f597c8be31ccb75a046629048e82be4d Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Thu, 7 Mar 2024 10:20:59 +0100 Subject: [PATCH] Shared Local Bundler E2E Setup --- .github/workflows/ci_4337.yml | 15 +- .github/workflows/ci_4337_gas_metering.yml | 9 +- .github/workflows/ci_4337_local_bundler.yml | 19 + .../workflows/ci_4337_upstream_bundler.yml | 7 +- .github/workflows/ci_passkey_example.yml | 4 - .prettierignore | 3 +- modules/4337/docker/bundler/Dockerfile | 12 - modules/4337/hardhat.config.ts | 8 +- modules/4337/package.json | 11 +- modules/4337/src/deploy/entrypoint.ts | 26 +- .../deploy/{webauthn.ts => experimental.ts} | 11 + modules/4337/src/deploy/libraries.ts | 2 - modules/4337/src/deploy/mock.ts | 1 - .../4337/src/deploy/{modules.ts => module.ts} | 1 - modules/4337/src/deploy/safe.ts | 40 +- modules/4337/test/e2e/4337NestedSafe.spec.ts | 2 +- modules/4337/test/e2e/LocalBundler.spec.ts | 2 +- .../4337/test/e2e/SingletonSigners.spec.ts | 2 +- modules/4337/test/e2e/UniqueSigner.spec.ts | 2 +- modules/4337/test/e2e/WebAuthnSigner.spec.ts | 2 +- .../test/e2e/WebAuthnSingletonSigner.spec.ts | 2 +- modules/4337/test/e2e/run.sh | 29 -- modules/allowances/package.json | 4 +- modules/passkey/docker-compose.yaml | 35 -- modules/passkey/hardhat.config.ts | 4 +- modules/passkey/package.json | 4 +- modules/passkey/src/deploy/entrypoint.ts | 3 + modules/passkey/src/deploy/safe.ts | 59 +-- modules/passkey/src/deploy/safe4337.ts | 33 ++ modules/passkey/src/deploy/webauthn.ts | 6 +- modules/passkey/test/4337/run.sh | 29 -- package-lock.json | 491 ++---------------- package.json | 3 +- packages/4337-local-bundler/.eslintignore | 1 + packages/4337-local-bundler/.gitignore | 1 + packages/4337-local-bundler/README.md | 3 + .../4337-local-bundler}/docker-compose.yaml | 4 + .../docker/bundler/Dockerfile | 1 + packages/4337-local-bundler/package.json | 22 + packages/4337-local-bundler/src/bin/test.ts | 68 +++ .../src/deploy/entrypoint.ts | 6 +- .../4337-local-bundler/src/deploy/safe.ts | 39 ++ packages/4337-local-bundler/src/index.ts | 6 + packages/4337-local-bundler/tsconfig.json | 13 + 44 files changed, 331 insertions(+), 714 deletions(-) create mode 100644 .github/workflows/ci_4337_local_bundler.yml delete mode 100644 modules/4337/docker/bundler/Dockerfile rename modules/4337/src/deploy/{webauthn.ts => experimental.ts} (75%) rename modules/4337/src/deploy/{modules.ts => module.ts} (95%) delete mode 100755 modules/4337/test/e2e/run.sh delete mode 100644 modules/passkey/docker-compose.yaml create mode 100644 modules/passkey/src/deploy/entrypoint.ts create mode 100644 modules/passkey/src/deploy/safe4337.ts delete mode 100755 modules/passkey/test/4337/run.sh create mode 100644 packages/4337-local-bundler/.eslintignore create mode 100644 packages/4337-local-bundler/.gitignore create mode 100644 packages/4337-local-bundler/README.md rename {modules/4337 => packages/4337-local-bundler}/docker-compose.yaml (83%) rename {modules/passkey => packages/4337-local-bundler}/docker/bundler/Dockerfile (99%) create mode 100644 packages/4337-local-bundler/package.json create mode 100644 packages/4337-local-bundler/src/bin/test.ts rename modules/passkey/src/deploy/4337.ts => packages/4337-local-bundler/src/deploy/entrypoint.ts (88%) create mode 100644 packages/4337-local-bundler/src/deploy/safe.ts create mode 100644 packages/4337-local-bundler/src/index.ts create mode 100644 packages/4337-local-bundler/tsconfig.json diff --git a/.github/workflows/ci_4337.yml b/.github/workflows/ci_4337.yml index ce63df2bd..df4b06f04 100644 --- a/.github/workflows/ci_4337.yml +++ b/.github/workflows/ci_4337.yml @@ -14,9 +14,9 @@ jobs: node-version: 20.x cache: npm cache-dependency-path: package-lock.json - - run: npm ci - - run: npm run build -w modules/4337 && npm run build:ts -w modules/4337 - - run: npm run coverage -w modules/4337 + - run: | + npm ci + npm run coverage -w modules/4337 - name: Coveralls uses: coverallsapp/github-action@master with: @@ -33,7 +33,7 @@ jobs: cache-dependency-path: package-lock.json - run: | npm ci - npm run test:e2e -w modules/4337 + npm run test:4337 -w modules/4337 lint: runs-on: ubuntu-latest steps: @@ -43,6 +43,7 @@ jobs: node-version: 20.x cache: npm cache-dependency-path: package-lock.json - - run: npm ci - - run: npm run lint -w modules/4337 - - run: npm run fmt:check -w modules/4337 + - run: | + npm ci + npm run lint -w modules/4337 + npm run fmt:check -w modules/4337 diff --git a/.github/workflows/ci_4337_gas_metering.yml b/.github/workflows/ci_4337_gas_metering.yml index c9abcb4d1..0262192c1 100644 --- a/.github/workflows/ci_4337_gas_metering.yml +++ b/.github/workflows/ci_4337_gas_metering.yml @@ -15,7 +15,8 @@ jobs: node-version: 20.x cache: npm cache-dependency-path: package-lock.json - - run: npm ci - - run: npm run fmt:check -w examples/4337-gas-metering - - run: npm run lint -w examples/4337-gas-metering - - run: npm run build -w examples/4337-gas-metering + - run: | + npm ci + npm run fmt:check -w examples/4337-gas-metering + npm run lint -w examples/4337-gas-metering + npm run build -w examples/4337-gas-metering diff --git a/.github/workflows/ci_4337_local_bundler.yml b/.github/workflows/ci_4337_local_bundler.yml new file mode 100644 index 000000000..62e4dddf1 --- /dev/null +++ b/.github/workflows/ci_4337_local_bundler.yml @@ -0,0 +1,19 @@ +name: safe-modules-4337-local-bundler +on: + push: + paths: + - 'packages/4337-local-bundler/**' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: npm + cache-dependency-path: package-lock.json + - run: | + npm ci + npm run lint -w packages/4337-local-bundler diff --git a/.github/workflows/ci_4337_upstream_bundler.yml b/.github/workflows/ci_4337_upstream_bundler.yml index ba60471a1..4f7f857e8 100644 --- a/.github/workflows/ci_4337_upstream_bundler.yml +++ b/.github/workflows/ci_4337_upstream_bundler.yml @@ -1,4 +1,4 @@ -name: 4337 Module End-to-End Tests With Upstream Bundler +name: 4337 End-to-End Tests With Upstream Bundler on: schedule: # * is a special character in YAML so you have to quote this string @@ -7,6 +7,8 @@ on: push: paths: - 'modules/4337/**' + - 'modules/passkey/**' + - 'packages/4337-local-bundler/**' jobs: e2e-upstream-bundler: @@ -20,4 +22,5 @@ jobs: cache-dependency-path: package-lock.json - run: | npm ci - npm run test:e2e:upstream -w modules/4337 + npm run test:4337:upstream -w modules/4337 + npm run test:4337:upstream -w modules/passkey diff --git a/.github/workflows/ci_passkey_example.yml b/.github/workflows/ci_passkey_example.yml index 9bd7f05cd..57ac18d63 100644 --- a/.github/workflows/ci_passkey_example.yml +++ b/.github/workflows/ci_passkey_example.yml @@ -17,10 +17,6 @@ jobs: cache: npm cache-dependency-path: package-lock.json - run: | - npm ci - # Build the 4337 module so the app can use the artifacts - npm run build -w modules/4337 - # Reinstall the dependencies so the 4337 dependency includes artifacts npm ci npm run lint -w examples/4337-passkeys npm run build -w examples/4337-passkeys diff --git a/.prettierignore b/.prettierignore index 3debc756e..dcc491490 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ -modules/** examples/** +modules/** +packages/** diff --git a/modules/4337/docker/bundler/Dockerfile b/modules/4337/docker/bundler/Dockerfile deleted file mode 100644 index 86b79b9f1..000000000 --- a/modules/4337/docker/bundler/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM docker.io/library/node:18 - -# v0.7.0 -ARG TAG=26e4f4c -RUN git clone https://github.com/eth-infinitism/bundler /src/bundler -WORKDIR /src/bundler -RUN git checkout ${TAG} -RUN git submodule init && git submodule update - -RUN yarn && yarn preprocess -ENTRYPOINT ["yarn", "bundler"] -CMD [] diff --git a/modules/4337/hardhat.config.ts b/modules/4337/hardhat.config.ts index 08df57c30..b257fd3d7 100644 --- a/modules/4337/hardhat.config.ts +++ b/modules/4337/hardhat.config.ts @@ -67,11 +67,11 @@ const userConfig: HardhatUserConfig = { networks: { localhost: { url: 'http://localhost:8545', - tags: ['dev', 'safe'], + tags: ['dev', 'entrypoint', 'safe'], }, hardhat: { gasPrice: 10000000000, - tags: ['test'], + tags: ['test', 'entrypoint', 'safe'], }, mainnet: { ...sharedNetworkConfig, @@ -88,12 +88,12 @@ const userConfig: HardhatUserConfig = { sepolia: { ...sharedNetworkConfig, url: `https://sepolia.infura.io/v3/${INFURA_KEY}`, - tags: ['dev'], + tags: ['dev', 'entrypoint'], }, amoy: { ...sharedNetworkConfig, url: `https://polygon-amoy.infura.io/v3/${INFURA_KEY}`, - tags: ['dev'], + tags: ['dev', 'entrypoint'], }, ...customNetwork, }, diff --git a/modules/4337/package.json b/modules/4337/package.json index 0212efa0a..c02830625 100644 --- a/modules/4337/package.json +++ b/modules/4337/package.json @@ -18,9 +18,9 @@ "build:ts": "npx rimraf dist && tsc", "build:sol": "npx rimraf build && hardhat compile", "test": "hardhat test --deploy-fixture", - "test:e2e": "./test/e2e/run.sh", - "test:e2e:upstream": "USE_UPSTREAM_BUNDLER=1 ./test/e2e/run.sh", - "test:all": "npm run test && npm run test:e2e", + "test:4337": "4337-local-bundler-test", + "test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test", + "test:all": "npm run test && npm run test:4337", "coverage": "hardhat coverage", "codesize": "hardhat codesize", "benchmark": "npm run test benchmark/*.ts", @@ -54,6 +54,7 @@ "@noble/curves": "^1.3.0", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@openzeppelin/contracts": "^5.0.2", + "@safe-global/safe-4337-local-bundler": "^0.0.0", "@simplewebauthn/server": "9.0.0", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", @@ -63,8 +64,8 @@ "debug": "^4.3.4", "dotenv": "^16.4.4", "ethers": "^6.11.1", - "hardhat": "^2.20.1", - "hardhat-deploy": "0.11.45", + "hardhat": "^2.21.0", + "hardhat-deploy": "^0.12.1", "husky": "^9.0.11", "solc": "^0.8.24", "solhint": "^4.1.1", diff --git a/modules/4337/src/deploy/entrypoint.ts b/modules/4337/src/deploy/entrypoint.ts index ff22afb76..5a7d29f06 100644 --- a/modules/4337/src/deploy/entrypoint.ts +++ b/modules/4337/src/deploy/entrypoint.ts @@ -1,25 +1,3 @@ -import EntryPoint from '@account-abstraction/contracts/artifacts/EntryPoint.json' -import { DeployFunction } from 'hardhat-deploy/types' +import { deployEntryPoint } from '@safe-global/safe-4337-local-bundler' -const ENTRY_POINT = process.env.DEPLOYMENT_ENTRY_POINT_ADDRESS - -const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { - const { deployer } = await getNamedAccounts() - const { deploy } = deployments - - if (network.tags.dev || network.tags.test) { - await deploy('EntryPoint', { - from: deployer, - contract: EntryPoint, - args: [], - log: true, - deterministicDeployment: '0x90d8084deab30c2a37c45e8d47f49f2f7965183cb6990a98943ef94940681de3', - }) - } else if (!ENTRY_POINT) { - throw new Error('DEPLOYMENT_ENTRY_POINT_ADDRESS must be set') - } -} - -deploy.tags = ['entrypoint'] - -export default deploy +export default deployEntryPoint diff --git a/modules/4337/src/deploy/webauthn.ts b/modules/4337/src/deploy/experimental.ts similarity index 75% rename from modules/4337/src/deploy/webauthn.ts rename to modules/4337/src/deploy/experimental.ts index 04f5636a4..e8f94b220 100644 --- a/modules/4337/src/deploy/webauthn.ts +++ b/modules/4337/src/deploy/experimental.ts @@ -8,6 +8,8 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network } const { deployer } = await getNamedAccounts() const { deploy } = deployments + const entryPoint = await deployments.get('EntryPoint') + const p256Verifier = await deploy('P256Verifier', { from: deployer, args: [], @@ -28,6 +30,15 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network } log: true, deterministicDeployment: true, }) + + await deploy('SafeSignerLaunchpad', { + from: deployer, + args: [entryPoint.address], + log: true, + deterministicDeployment: true, + }) } +deploy.dependencies = ['entrypoint'] + export default deploy diff --git a/modules/4337/src/deploy/libraries.ts b/modules/4337/src/deploy/libraries.ts index c3cfe75d4..a840f10d9 100644 --- a/modules/4337/src/deploy/libraries.ts +++ b/modules/4337/src/deploy/libraries.ts @@ -12,6 +12,4 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => { }) } -deploy.tags = ['libraries'] - export default deploy diff --git a/modules/4337/src/deploy/mock.ts b/modules/4337/src/deploy/mock.ts index 41e712069..3d1f5f946 100644 --- a/modules/4337/src/deploy/mock.ts +++ b/modules/4337/src/deploy/mock.ts @@ -28,6 +28,5 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network } } deploy.dependencies = ['entrypoint'] -deploy.tags = ['mock'] export default deploy diff --git a/modules/4337/src/deploy/modules.ts b/modules/4337/src/deploy/module.ts similarity index 95% rename from modules/4337/src/deploy/modules.ts rename to modules/4337/src/deploy/module.ts index a46e020ac..b4f4b4208 100644 --- a/modules/4337/src/deploy/modules.ts +++ b/modules/4337/src/deploy/module.ts @@ -17,6 +17,5 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => { } deploy.dependencies = ['entrypoint'] -deploy.tags = ['modules'] export default deploy diff --git a/modules/4337/src/deploy/safe.ts b/modules/4337/src/deploy/safe.ts index b7f0c9c0e..9a91a3377 100644 --- a/modules/4337/src/deploy/safe.ts +++ b/modules/4337/src/deploy/safe.ts @@ -1,39 +1,3 @@ -import MultiSend from '@safe-global/safe-contracts/build/artifacts/contracts/libraries/MultiSend.sol/MultiSend.json' -import SafeProxyFactory from '@safe-global/safe-contracts/build/artifacts/contracts/proxies/SafeProxyFactory.sol/SafeProxyFactory.json' -import SafeL2 from '@safe-global/safe-contracts/build/artifacts/contracts/SafeL2.sol/SafeL2.json' -import { DeployFunction } from 'hardhat-deploy/types' +import { deploySafe } from '@safe-global/safe-4337-local-bundler' -const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { - if (!network.tags.safe && !network.tags.test) { - return - } - - const { deployer } = await getNamedAccounts() - const { deploy } = deployments - - await deploy('MultiSend', { - from: deployer, - contract: MultiSend, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('SafeL2', { - from: deployer, - contract: SafeL2, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('SafeProxyFactory', { - from: deployer, - contract: SafeProxyFactory, - args: [], - log: true, - deterministicDeployment: true, - }) -} - -deploy.tags = ['safe'] - -export default deploy +export default deploySafe diff --git a/modules/4337/test/e2e/4337NestedSafe.spec.ts b/modules/4337/test/e2e/4337NestedSafe.spec.ts index 6059fdebc..449068ba4 100644 --- a/modules/4337/test/e2e/4337NestedSafe.spec.ts +++ b/modules/4337/test/e2e/4337NestedSafe.spec.ts @@ -290,7 +290,7 @@ const buildNestedSafeOp = async ( ) } -describe('E2E - Nested Safes With An Execution Initiated by a Leaf 4337 Safe', () => { +describe('Nested Safes With An Execution Initiated by a Leaf 4337 Safe [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/LocalBundler.spec.ts b/modules/4337/test/e2e/LocalBundler.spec.ts index fef9561df..7c7bdd158 100644 --- a/modules/4337/test/e2e/LocalBundler.spec.ts +++ b/modules/4337/test/e2e/LocalBundler.spec.ts @@ -6,7 +6,7 @@ import { chainId, timestamp } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' -describe('E2E - Local Bundler', () => { +describe('Local Bundler [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/SingletonSigners.spec.ts b/modules/4337/test/e2e/SingletonSigners.spec.ts index 134cb76e1..d7b977918 100644 --- a/modules/4337/test/e2e/SingletonSigners.spec.ts +++ b/modules/4337/test/e2e/SingletonSigners.spec.ts @@ -8,7 +8,7 @@ import { } from '../../src/utils/userOp' import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e' -describe('E2E - Singleton Signers', () => { +describe('Singleton Signers [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/UniqueSigner.spec.ts b/modules/4337/test/e2e/UniqueSigner.spec.ts index 16a100834..dc923ded9 100644 --- a/modules/4337/test/e2e/UniqueSigner.spec.ts +++ b/modules/4337/test/e2e/UniqueSigner.spec.ts @@ -4,7 +4,7 @@ import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' import { chainId } from '../utils/encoding' import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp' -describe('E2E - Unique Signers', () => { +describe('Unique Signers [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/WebAuthnSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSigner.spec.ts index 5f8f3165d..bdb51052b 100644 --- a/modules/4337/test/e2e/WebAuthnSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSigner.spec.ts @@ -11,7 +11,7 @@ import { } from '../utils/webauthn' import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp' -describe('E2E - WebAuthn Signers', () => { +describe('WebAuthn Signers [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts index e61ad22f4..50eb3d408 100644 --- a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts @@ -15,7 +15,7 @@ import { } from '../../src/utils/userOp' import { buildSignatureBytes } from '../../src/utils/execution' -describe('E2E - WebAuthn Singleton Signers', () => { +describe('WebAuthn Singleton Signers [@4337]', () => { before(function () { if (network.name !== 'localhost') { this.skip() diff --git a/modules/4337/test/e2e/run.sh b/modules/4337/test/e2e/run.sh deleted file mode 100755 index 3a77a3280..000000000 --- a/modules/4337/test/e2e/run.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -DOCKER="${DOCKER:-docker}" - -bundler_container="bundler" -if [[ -n "$USE_UPSTREAM_BUNDLER" ]]; then - bundler_container="bundler-upstream" -fi - -"$DOCKER" compose up -d geth "$bundler_container" - -# wait for containers to start up -SECONDS=0 -until curl -fs http://localhost:8545 >/dev/null && curl -fs http://localhost:3000 >/dev/null; do - if [[ $SECONDS -gt 30 ]]; then - echo "ERROR: timeout waiting for local node and bundler to start" - "$DOCKER" compose logs - exit 1 - fi - sleep 1 -done - -hardhat test --deploy-fixture --network localhost --grep '^E2E - ' -success=$? - -"$DOCKER" compose down - -# exit with the E2E test's exit code -exit $success diff --git a/modules/allowances/package.json b/modules/allowances/package.json index ac00c787d..e35e93616 100644 --- a/modules/allowances/package.json +++ b/modules/allowances/package.json @@ -42,8 +42,8 @@ "chai": "^4.2.0", "dotenv": "^16.4.4", "ethers": "^6.11.1", - "hardhat": "^2.20.1", - "hardhat-deploy": "^0.11.45", + "hardhat": "^2.21.0", + "hardhat-deploy": "^0.12.1", "hardhat-gas-reporter": "^1.0.10", "rimraf": "^5.0.5", "solhint": "4.1.1", diff --git a/modules/passkey/docker-compose.yaml b/modules/passkey/docker-compose.yaml deleted file mode 100644 index fee33d682..000000000 --- a/modules/passkey/docker-compose.yaml +++ /dev/null @@ -1,35 +0,0 @@ -version: '3.8' - -services: - geth: - image: docker.io/ethereum/client-go:stable - restart: always - environment: - GETH_DEV: 'true' - GETH_HTTP: 'true' - GETH_HTTP_ADDR: '0.0.0.0' - GETH_HTTP_API: 'personal,eth,net,web3,debug' - GETH_HTTP_VHOSTS: '*' - GETH_RPC_ALLOW_UNPROTECTED_TXS: 'true' - ports: - - 8545:8545 - - bundler: - build: - context: . - dockerfile: docker/bundler/Dockerfile - restart: always - command: ['--auto', '--network=http://geth:8545'] - ports: - - 3000:3000 - - bundler-upstream: - build: - context: . - dockerfile: docker/bundler/Dockerfile - args: - TAG: main - restart: always - command: ['--auto', '--network=http://geth:8545'] - ports: - - 3000:3000 diff --git a/modules/passkey/hardhat.config.ts b/modules/passkey/hardhat.config.ts index 405a5b7bb..7ca871482 100644 --- a/modules/passkey/hardhat.config.ts +++ b/modules/passkey/hardhat.config.ts @@ -15,10 +15,10 @@ const config: HardhatUserConfig = { networks: { localhost: { url: 'http://localhost:8545', - tags: ['dev'], + tags: ['dev', 'entrypoint', 'safe'], }, hardhat: { - tags: ['test'], + tags: ['test', 'entrypoint', 'safe'], }, }, solidity: { diff --git a/modules/passkey/package.json b/modules/passkey/package.json index a52477edf..7eb510bcd 100644 --- a/modules/passkey/package.json +++ b/modules/passkey/package.json @@ -37,13 +37,15 @@ "lint:sol": "solhint 'contracts/**/*.sol'", "lint:ts": "eslint .", "test": "hardhat test", - "test:4337": "./test/4337/run.sh" + "test:4337": "4337-local-bundler-test", + "test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test" }, "devDependencies": { "@account-abstraction/contracts": "^0.7.0", "@noble/curves": "^1.3.0", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@safe-global/safe-4337": "^0.3.0", + "@safe-global/safe-4337-local-bundler": "^0.0.0", "@simplewebauthn/server": "^9.0.3", "cbor": "^9.0.2", "dotenv": "^16.4.5", diff --git a/modules/passkey/src/deploy/entrypoint.ts b/modules/passkey/src/deploy/entrypoint.ts new file mode 100644 index 000000000..5a7d29f06 --- /dev/null +++ b/modules/passkey/src/deploy/entrypoint.ts @@ -0,0 +1,3 @@ +import { deployEntryPoint } from '@safe-global/safe-4337-local-bundler' + +export default deployEntryPoint diff --git a/modules/passkey/src/deploy/safe.ts b/modules/passkey/src/deploy/safe.ts index 5137033aa..9a91a3377 100644 --- a/modules/passkey/src/deploy/safe.ts +++ b/modules/passkey/src/deploy/safe.ts @@ -1,58 +1,3 @@ -import MultiSend from '@safe-global/safe-contracts/build/artifacts/contracts/libraries/MultiSend.sol/MultiSend.json' -import SafeProxyFactory from '@safe-global/safe-contracts/build/artifacts/contracts/proxies/SafeProxyFactory.sol/SafeProxyFactory.json' -import SafeL2 from '@safe-global/safe-contracts/build/artifacts/contracts/SafeL2.sol/SafeL2.json' -import Safe4337Module from '@safe-global/safe-4337/build/artifacts/contracts/Safe4337Module.sol/Safe4337Module.json' -import SafeModuleSetup from '@safe-global/safe-4337/build/artifacts/contracts/SafeModuleSetup.sol/SafeModuleSetup.json' -import { DeployFunction } from 'hardhat-deploy/types' +import { deploySafe } from '@safe-global/safe-4337-local-bundler' -const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { - if (!network.tags.dev && !network.tags.test) { - return - } - - const { deployer } = await getNamedAccounts() - const { deploy } = deployments - - const entryPoint = await deployments.get('EntryPoint') - - await deploy('MultiSend', { - from: deployer, - contract: MultiSend, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('SafeL2', { - from: deployer, - contract: SafeL2, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('SafeProxyFactory', { - from: deployer, - contract: SafeProxyFactory, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('SafeModuleSetup', { - from: deployer, - contract: SafeModuleSetup, - args: [], - log: true, - deterministicDeployment: true, - }) - await deploy('Safe4337Module', { - from: deployer, - contract: Safe4337Module, - args: [entryPoint.address], - log: true, - deterministicDeployment: true, - }) -} - -deploy.dependencies = ['entrypoint'] -deploy.tags = ['safe'] - -export default deploy +export default deploySafe diff --git a/modules/passkey/src/deploy/safe4337.ts b/modules/passkey/src/deploy/safe4337.ts new file mode 100644 index 000000000..a77960062 --- /dev/null +++ b/modules/passkey/src/deploy/safe4337.ts @@ -0,0 +1,33 @@ +import Safe4337Module from '@safe-global/safe-4337/build/artifacts/contracts/Safe4337Module.sol/Safe4337Module.json' +import SafeModuleSetup from '@safe-global/safe-4337/build/artifacts/contracts/SafeModuleSetup.sol/SafeModuleSetup.json' +import { DeployFunction } from 'hardhat-deploy/types' + +const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { + if (!network.tags.safe) { + return + } + + const { deployer } = await getNamedAccounts() + const { deploy } = deployments + + const entryPoint = await deployments.get('EntryPoint') + + await deploy('SafeModuleSetup', { + from: deployer, + contract: SafeModuleSetup, + args: [], + log: true, + deterministicDeployment: true, + }) + await deploy('Safe4337Module', { + from: deployer, + contract: Safe4337Module, + args: [entryPoint.address], + log: true, + deterministicDeployment: true, + }) +} + +deploy.dependencies = ['entrypoint'] + +export default deploy diff --git a/modules/passkey/src/deploy/webauthn.ts b/modules/passkey/src/deploy/webauthn.ts index 6fc7f6a04..38dbb51df 100644 --- a/modules/passkey/src/deploy/webauthn.ts +++ b/modules/passkey/src/deploy/webauthn.ts @@ -1,10 +1,6 @@ import { DeployFunction } from 'hardhat-deploy/types' -const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { - if (!network.tags.dev && !network.tags.test) { - return - } - +const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => { const { deployer } = await getNamedAccounts() const { deploy } = deployments diff --git a/modules/passkey/test/4337/run.sh b/modules/passkey/test/4337/run.sh deleted file mode 100755 index 943f2a359..000000000 --- a/modules/passkey/test/4337/run.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -DOCKER="${DOCKER:-docker}" - -bundler_container="bundler" -if [[ -n "$USE_UPSTREAM_BUNDLER" ]]; then - bundler_container="bundler-upstream" -fi - -"$DOCKER" compose up -d geth "$bundler_container" - -# wait for containers to start up -SECONDS=0 -until curl -fs http://localhost:8545 >/dev/null && curl -fs http://localhost:3000 >/dev/null; do - if [[ $SECONDS -gt 30 ]]; then - echo "ERROR: timeout waiting for local node and bundler to start" - "$DOCKER" compose logs - exit 1 - fi - sleep 1 -done - -hardhat test --deploy-fixture --network localhost --grep '@4337' -success=$? - -"$DOCKER" compose down - -# exit with the E2E test's exit code -exit $success diff --git a/package-lock.json b/package-lock.json index fbc5a0354..a26ac5fe0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -568,6 +568,7 @@ "@noble/curves": "^1.3.0", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@openzeppelin/contracts": "^5.0.2", + "@safe-global/safe-4337-local-bundler": "^0.0.0", "@simplewebauthn/server": "9.0.0", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", @@ -577,8 +578,8 @@ "debug": "^4.3.4", "dotenv": "^16.4.4", "ethers": "^6.11.1", - "hardhat": "^2.20.1", - "hardhat-deploy": "0.11.45", + "hardhat": "^2.21.0", + "hardhat-deploy": "^0.12.1", "husky": "^9.0.11", "solc": "^0.8.24", "solhint": "^4.1.1", @@ -908,8 +909,8 @@ "chai": "^4.2.0", "dotenv": "^16.4.4", "ethers": "^6.11.1", - "hardhat": "^2.20.1", - "hardhat-deploy": "^0.11.45", + "hardhat": "^2.21.0", + "hardhat-deploy": "^0.12.1", "hardhat-gas-reporter": "^1.0.10", "rimraf": "^5.0.5", "solhint": "4.1.1", @@ -1190,6 +1191,7 @@ "@noble/curves": "^1.3.0", "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@safe-global/safe-4337": "^0.3.0", + "@safe-global/safe-4337-local-bundler": "^0.0.0", "@simplewebauthn/server": "^9.0.3", "cbor": "^9.0.2", "dotenv": "^16.4.5", @@ -1204,213 +1206,6 @@ "license": "MIT", "peer": true }, - "modules/passkey/node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "modules/passkey/node_modules/@ethersproject/json-wallets/node_modules/aes-js": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, - "modules/passkey/node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/units": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "modules/passkey/node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, "modules/passkey/node_modules/@noble/curves": { "version": "1.2.0", "dev": true, @@ -1525,51 +1320,6 @@ "license": "MIT", "peer": true }, - "modules/passkey/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "modules/passkey/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "modules/passkey/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "modules/passkey/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, "modules/passkey/node_modules/dotenv": { "version": "16.4.5", "dev": true, @@ -1624,109 +1374,11 @@ "node": ">=10" } }, - "modules/passkey/node_modules/hardhat-deploy": { - "version": "0.12.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/contracts": "^5.7.0", - "@ethersproject/providers": "^5.7.2", - "@ethersproject/solidity": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wallet": "^5.7.0", - "@types/qs": "^6.9.7", - "axios": "^0.21.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "ethers": "^5.7.0", - "form-data": "^4.0.0", - "fs-extra": "^10.0.0", - "match-all": "^1.2.6", - "murmur-128": "^0.2.1", - "qs": "^6.9.4", - "zksync-ethers": "^5.0.0" - } - }, - "modules/passkey/node_modules/hardhat-deploy/node_modules/ethers": { - "version": "5.7.2", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - }, - "modules/passkey/node_modules/hardhat-deploy/node_modules/fs-extra": { - "version": "10.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "modules/passkey/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "modules/passkey/node_modules/jsonfile": { "version": "6.1.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -1734,17 +1386,6 @@ "graceful-fs": "^4.1.6" } }, - "modules/passkey/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "modules/passkey/node_modules/tslib": { "version": "2.4.0", "dev": true, @@ -1755,6 +1396,7 @@ "version": "2.0.1", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -3886,6 +3528,10 @@ "resolved": "modules/4337", "link": true }, + "node_modules/@safe-global/safe-4337-local-bundler": { + "resolved": "packages/4337-local-bundler", + "link": true + }, "node_modules/@safe-global/safe-allowance-module": { "resolved": "modules/allowances", "link": true @@ -4480,7 +4126,6 @@ }, "node_modules/@types/qs": { "version": "6.9.11", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { @@ -5552,7 +5197,6 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5842,7 +5486,6 @@ }, "node_modules/axios": { "version": "0.21.4", - "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.14.0" @@ -6137,7 +5780,6 @@ }, "node_modules/call-bind": { "version": "1.0.5", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2", @@ -6803,7 +6445,6 @@ }, "node_modules/define-data-property": { "version": "1.1.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.1", @@ -6973,7 +6614,6 @@ }, "node_modules/enquirer": { "version": "2.4.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", @@ -8985,7 +8625,6 @@ }, "node_modules/fmix": { "version": "0.1.0", - "dev": true, "license": "MIT", "dependencies": { "imul": "^1.0.0" @@ -9082,7 +8721,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9130,7 +8768,6 @@ }, "node_modules/get-intrinsic": { "version": "1.2.2", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2", @@ -9327,7 +8964,6 @@ }, "node_modules/gopd": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -9362,7 +8998,6 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, "license": "ISC" }, "node_modules/graphemer": { @@ -9407,8 +9042,9 @@ }, "node_modules/hardhat": { "version": "2.21.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.21.0.tgz", + "integrity": "sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw==", "dev": true, - "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", @@ -9471,9 +9107,9 @@ } }, "node_modules/hardhat-deploy": { - "version": "0.11.45", - "dev": true, - "license": "MIT", + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.12.1.tgz", + "integrity": "sha512-ayPJqBCElzPeiwdHUEV0rKQ6NvKStjQAxCqCPlsavQVaxl7uZUHt/d+XbLqglVFqOOpHHs6L9K4W1vxPbsOy5Q==", "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -9498,12 +9134,13 @@ "match-all": "^1.2.6", "murmur-128": "^0.2.1", "qs": "^6.9.4", - "zksync-web3": "^0.14.3" + "zksync-ethers": "^5.0.0" } }, "node_modules/hardhat-deploy/node_modules/@ethersproject/contracts": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", "funding": [ { "type": "individual", @@ -9514,7 +9151,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0", @@ -9530,7 +9166,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/hdnode": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", "funding": [ { "type": "individual", @@ -9541,7 +9178,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/basex": "^5.7.0", @@ -9559,7 +9195,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/json-wallets": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", "funding": [ { "type": "individual", @@ -9570,7 +9207,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/address": "^5.7.0", @@ -9589,7 +9225,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/pbkdf2": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", "funding": [ { "type": "individual", @@ -9600,7 +9237,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/sha2": "^5.7.0" @@ -9608,7 +9244,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/solidity": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", "funding": [ { "type": "individual", @@ -9619,7 +9256,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/bytes": "^5.7.0", @@ -9631,7 +9267,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/units": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", "funding": [ { "type": "individual", @@ -9642,7 +9279,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bignumber": "^5.7.0", "@ethersproject/constants": "^5.7.0", @@ -9651,7 +9287,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/wallet": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", "funding": [ { "type": "individual", @@ -9662,7 +9299,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -9683,7 +9319,8 @@ }, "node_modules/hardhat-deploy/node_modules/@ethersproject/wordlists": { "version": "5.7.0", - "dev": true, + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", "funding": [ { "type": "individual", @@ -9694,7 +9331,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", @@ -9705,12 +9341,11 @@ }, "node_modules/hardhat-deploy/node_modules/aes-js": { "version": "3.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==" }, "node_modules/hardhat-deploy/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -9724,7 +9359,6 @@ }, "node_modules/hardhat-deploy/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -9739,7 +9373,6 @@ }, "node_modules/hardhat-deploy/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -9750,12 +9383,12 @@ }, "node_modules/hardhat-deploy/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/hardhat-deploy/node_modules/ethers": { "version": "5.7.2", - "dev": true, + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", "funding": [ { "type": "individual", @@ -9766,7 +9399,6 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "license": "MIT", "dependencies": { "@ethersproject/abi": "5.7.0", "@ethersproject/abstract-provider": "5.7.0", @@ -9802,7 +9434,6 @@ }, "node_modules/hardhat-deploy/node_modules/fs-extra": { "version": "10.1.0", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -9815,7 +9446,6 @@ }, "node_modules/hardhat-deploy/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9823,7 +9453,6 @@ }, "node_modules/hardhat-deploy/node_modules/jsonfile": { "version": "6.1.0", - "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -9834,7 +9463,6 @@ }, "node_modules/hardhat-deploy/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -9845,20 +9473,11 @@ }, "node_modules/hardhat-deploy/node_modules/universalify": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" } }, - "node_modules/hardhat-deploy/node_modules/zksync-web3": { - "version": "0.14.4", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ethers": "^5.7.0" - } - }, "node_modules/hardhat-gas-reporter": { "version": "1.0.10", "dev": true, @@ -9890,7 +9509,6 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.2" @@ -9901,7 +9519,6 @@ }, "node_modules/has-proto": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9912,7 +9529,6 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9977,7 +9593,6 @@ }, "node_modules/hasown": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -10175,7 +9790,6 @@ }, "node_modules/imul": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11070,7 +10684,6 @@ }, "node_modules/match-all": { "version": "1.2.6", - "dev": true, "license": "MIT" }, "node_modules/md5.js": { @@ -11427,7 +11040,6 @@ }, "node_modules/murmur-128": { "version": "0.2.1", - "dev": true, "license": "MIT", "dependencies": { "encode-utf8": "^1.0.2", @@ -11612,7 +11224,6 @@ }, "node_modules/object-inspect": { "version": "1.13.1", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -12407,7 +12018,6 @@ }, "node_modules/qs": { "version": "6.11.2", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" @@ -13041,7 +12651,6 @@ }, "node_modules/set-function-length": { "version": "1.1.1", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.1", @@ -13134,7 +12743,6 @@ }, "node_modules/side-channel": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -15268,7 +14876,6 @@ }, "node_modules/zksync-ethers": { "version": "5.4.0", - "dev": true, "license": "MIT", "dependencies": { "ethers": "~5.7.0" @@ -15279,7 +14886,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/contracts": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15306,7 +14912,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/hdnode": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15335,7 +14940,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/json-wallets": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15365,7 +14969,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/pbkdf2": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15384,7 +14987,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/solidity": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15407,7 +15009,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/units": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15427,7 +15028,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/wallet": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15459,7 +15059,6 @@ }, "node_modules/zksync-ethers/node_modules/@ethersproject/wordlists": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -15481,12 +15080,10 @@ }, "node_modules/zksync-ethers/node_modules/aes-js": { "version": "3.0.0", - "dev": true, "license": "MIT" }, "node_modules/zksync-ethers/node_modules/ethers": { "version": "5.7.2", - "dev": true, "funding": [ { "type": "individual", @@ -15537,6 +15134,18 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "packages/4337-local-bundler": { + "name": "@safe-global/safe-4337-local-bundler", + "version": "0.0.0", + "hasInstallScript": true, + "license": "LGPL-3.0-only", + "dependencies": { + "hardhat-deploy": "^0.12.1" + }, + "bin": { + "local-bundler-test": "dist/bin/test.js" + } } } } diff --git a/package.json b/package.json index 2dd1df5d7..aa48f7437 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ ], "scripts": { "fmt:global": "prettier --write .", - "fmt:global-check": "prettier --check ." + "fmt:global-check": "prettier --check .", + "postinstall": "npm rebuild --skip-scripts @safe-global/safe-4337-local-bundler" }, "repository": { "type": "git", diff --git a/packages/4337-local-bundler/.eslintignore b/packages/4337-local-bundler/.eslintignore new file mode 100644 index 000000000..849ddff3b --- /dev/null +++ b/packages/4337-local-bundler/.eslintignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/4337-local-bundler/.gitignore b/packages/4337-local-bundler/.gitignore new file mode 100644 index 000000000..849ddff3b --- /dev/null +++ b/packages/4337-local-bundler/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/4337-local-bundler/README.md b/packages/4337-local-bundler/README.md new file mode 100644 index 000000000..5f24a4bfd --- /dev/null +++ b/packages/4337-local-bundler/README.md @@ -0,0 +1,3 @@ +# ERC-4337 Local Bundler + +This repository contains tools for setting up and using a local ERC-4337 bundler for testing. While on-chain compatibility with the ERC-4337 `EntryPoint` contract is important, arguably the most challenging part of being compatible with the standard is ensuring that the account follows the user operation validation and account deployment rules that are enforced by the off-chain bundlers. As such, this repository provides tools to run a local development node with the reference ERC-4337 bundler for testing purposes. diff --git a/modules/4337/docker-compose.yaml b/packages/4337-local-bundler/docker-compose.yaml similarity index 83% rename from modules/4337/docker-compose.yaml rename to packages/4337-local-bundler/docker-compose.yaml index fee33d682..6ccfae84c 100644 --- a/modules/4337/docker-compose.yaml +++ b/packages/4337-local-bundler/docker-compose.yaml @@ -20,6 +20,8 @@ services: dockerfile: docker/bundler/Dockerfile restart: always command: ['--auto', '--network=http://geth:8545'] + environment: + DEBUG: 'aa.exec,aa.exec.cron,aa.events,aa.mempool' ports: - 3000:3000 @@ -31,5 +33,7 @@ services: TAG: main restart: always command: ['--auto', '--network=http://geth:8545'] + environment: + DEBUG: 'aa.exec,aa.exec.cron,aa.events,aa.mempool' ports: - 3000:3000 diff --git a/modules/passkey/docker/bundler/Dockerfile b/packages/4337-local-bundler/docker/bundler/Dockerfile similarity index 99% rename from modules/passkey/docker/bundler/Dockerfile rename to packages/4337-local-bundler/docker/bundler/Dockerfile index 86b79b9f1..61ed0c454 100644 --- a/modules/passkey/docker/bundler/Dockerfile +++ b/packages/4337-local-bundler/docker/bundler/Dockerfile @@ -2,6 +2,7 @@ FROM docker.io/library/node:18 # v0.7.0 ARG TAG=26e4f4c + RUN git clone https://github.com/eth-infinitism/bundler /src/bundler WORKDIR /src/bundler RUN git checkout ${TAG} diff --git a/packages/4337-local-bundler/package.json b/packages/4337-local-bundler/package.json new file mode 100644 index 000000000..ceaf6e913 --- /dev/null +++ b/packages/4337-local-bundler/package.json @@ -0,0 +1,22 @@ +{ + "name": "@safe-global/safe-4337-local-bundler", + "version": "0.0.0", + "private": true, + "license": "LGPL-3.0-only", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "4337-local-bundler-test": "dist/bin/test.js" + }, + "scripts": { + "build": "npx rimraf dist && tsc && chmod +x dist/bin/*.js", + "lint": "eslint .", + "prepack": "npm run build", + "prepublish": "npm run build", + "postinstall": "npm run build" + }, + "dependencies": { + "hardhat-deploy": "^0.12.1", + "node-fetch": "^2.7.0" + } +} diff --git a/packages/4337-local-bundler/src/bin/test.ts b/packages/4337-local-bundler/src/bin/test.ts new file mode 100644 index 000000000..bd6a98538 --- /dev/null +++ b/packages/4337-local-bundler/src/bin/test.ts @@ -0,0 +1,68 @@ +#!/usr/bin/env node + +import childProcess, { SpawnOptions } from 'node:child_process' +import path from 'node:path' + +const { DOCKER, USE_UPSTREAM_BUNDLER } = process.env + +const root = path.join(__dirname, '..', '..') + +const docker = DOCKER || 'docker' +const bundler = USE_UPSTREAM_BUNDLER === '1' ? 'bundler-upstream' : 'bundler' + +async function exec(command: string, args: string[], options: Omit = {}) { + const process = childProcess.spawn(command, args, { ...options, stdio: 'inherit' }) + await new Promise((resolve, reject) => { + process.on('exit', (code) => { + if (code === 0) { + resolve(undefined) + } else { + reject(new Error(`'${command}' process exited with code ${code}`)) + } + }) + }) +} + +async function checkRpc(...urls: string[]) { + const statuses = await Promise.all( + urls.map(async (url) => { + try { + const response = await fetch(url) + return response.ok + } catch (err) { + return false + } + }), + ) + return statuses.every((ok) => ok) +} + +async function main() { + console.log('==> Starting docker containers...') + await exec(docker, ['compose', 'up', '-d', 'geth', bundler], { cwd: root }) + + console.log('==> Waiting for RPC endpoints') + const start = Date.now() + const timeout = 60 * 1000 + while (!(await checkRpc('http://localhost:8545', 'http://localhost:3000'))) { + if (Date.now() - start > timeout) { + throw new Error('timeout waiting for local node and bundler to start') + } + } + + try { + console.log('==> Running tests') + await exec('hardhat', ['test', '--network', 'localhost', '--grep', '@4337']) + } finally { + console.log('==> Shutting down') + await exec(docker, ['compose', 'down'], { cwd: root }) + } +} + +main().catch((err) => { + console.error('ERROR: ', err) + if (err.stderr) { + console.log(err.stderr) + } + process.exitCode = 1 +}) diff --git a/modules/passkey/src/deploy/4337.ts b/packages/4337-local-bundler/src/deploy/entrypoint.ts similarity index 88% rename from modules/passkey/src/deploy/4337.ts rename to packages/4337-local-bundler/src/deploy/entrypoint.ts index 1b86a7e6c..8983b69bc 100644 --- a/modules/passkey/src/deploy/4337.ts +++ b/packages/4337-local-bundler/src/deploy/entrypoint.ts @@ -1,7 +1,11 @@ import EntryPoint from '@account-abstraction/contracts/artifacts/EntryPoint.json' import { DeployFunction } from 'hardhat-deploy/types' -const deploy: DeployFunction = async ({ deployments, getNamedAccounts }) => { +const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { + if (!network.tags.entrypoint) { + return + } + const { deployer } = await getNamedAccounts() const { deploy } = deployments diff --git a/packages/4337-local-bundler/src/deploy/safe.ts b/packages/4337-local-bundler/src/deploy/safe.ts new file mode 100644 index 000000000..1e6749ffb --- /dev/null +++ b/packages/4337-local-bundler/src/deploy/safe.ts @@ -0,0 +1,39 @@ +import MultiSend from '@safe-global/safe-contracts/build/artifacts/contracts/libraries/MultiSend.sol/MultiSend.json' +import SafeProxyFactory from '@safe-global/safe-contracts/build/artifacts/contracts/proxies/SafeProxyFactory.sol/SafeProxyFactory.json' +import SafeL2 from '@safe-global/safe-contracts/build/artifacts/contracts/SafeL2.sol/SafeL2.json' +import { DeployFunction } from 'hardhat-deploy/types' + +const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }) => { + if (!network.tags.safe) { + return + } + + const { deployer } = await getNamedAccounts() + const { deploy } = deployments + + await deploy('MultiSend', { + from: deployer, + contract: MultiSend, + args: [], + log: true, + deterministicDeployment: true, + }) + await deploy('SafeL2', { + from: deployer, + contract: SafeL2, + args: [], + log: true, + deterministicDeployment: true, + }) + await deploy('SafeProxyFactory', { + from: deployer, + contract: SafeProxyFactory, + args: [], + log: true, + deterministicDeployment: true, + }) +} + +deploy.tags = ['safe'] + +export default deploy diff --git a/packages/4337-local-bundler/src/index.ts b/packages/4337-local-bundler/src/index.ts new file mode 100644 index 000000000..3d2da4d3a --- /dev/null +++ b/packages/4337-local-bundler/src/index.ts @@ -0,0 +1,6 @@ +import 'hardhat-deploy' + +import deployEntryPoint from './deploy/entrypoint' +import deploySafe from './deploy/safe' + +export { deployEntryPoint, deploySafe } diff --git a/packages/4337-local-bundler/tsconfig.json b/packages/4337-local-bundler/tsconfig.json new file mode 100644 index 000000000..0ae3997d0 --- /dev/null +++ b/packages/4337-local-bundler/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "declaration": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true + } +}