From a00c26409d4b600dfc86d9b7d111e21f996876a1 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Mon, 18 Mar 2024 15:16:57 +0100 Subject: [PATCH 1/3] Shared Local Bundler E2E Setup (#314) This PR adds a new workspace `packages/4337-local-bundler` which exposes a `bin` executable called `4337-local-bundler-test` which runs a local bundler using Docker, and then executes `hardhat` tests using the `@4337` tag. This allows us to have a homogeneous setup between both the 4337 and passkey repositories (as well as any future modules that we want to be 4337-compliant). Along the way, I was also able to share 4337 and Safe deployment scripts across the projects when bootstrapping the local development node. --- .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 ce63df2b..df4b06f0 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 c9abcb4d..0262192c 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 00000000..62e4dddf --- /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 ba60471a..4f7f857e 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 9bd7f05c..57ac18d6 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 3debc756..dcc49149 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 86b79b9f..00000000 --- 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 08df57c3..b257fd3d 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 0212efa0..c0283062 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 ff22afb7..5a7d29f0 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 04f5636a..e8f94b22 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 c3cfe75d..a840f10d 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 41e71206..3d1f5f94 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 a46e020a..b4f4b420 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 b7f0c9c0..9a91a337 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 6059fdeb..449068ba 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 fef9561d..7c7bdd15 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 134cb76e..d7b97791 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 16a10083..dc923ded 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 5f8f3165..bdb51052 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 e61ad22f..50eb3d40 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 3a77a328..00000000 --- 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 ac00c787..e35e9361 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 fee33d68..00000000 --- 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 405a5b7b..7ca87148 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 a52477ed..7eb510bc 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 00000000..5a7d29f0 --- /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 5137033a..9a91a337 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 00000000..a7796006 --- /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 6fc7f6a0..38dbb51d 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 943f2a35..00000000 --- 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 fbc5a035..a26ac5fe 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 2dd1df5d..aa48f743 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 00000000..849ddff3 --- /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 00000000..849ddff3 --- /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 00000000..5f24a4bf --- /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 fee33d68..6ccfae84 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 86b79b9f..61ed0c45 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 00000000..ceaf6e91 --- /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 00000000..bd6a9853 --- /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 1b86a7e6..8983b69b 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 00000000..1e6749ff --- /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 00000000..3d2da4d3 --- /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 00000000..0ae3997d --- /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 + } +} From 232e71b737bad9b0573665a9a40d5437dd267048 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Mon, 18 Mar 2024 15:28:11 +0100 Subject: [PATCH 2/3] Move 4337 Testing Utilies To Local Bundler Package (#315) This PR moves the TS testing utility code for 4337 local bundler tests into the package introduced in #314. This is done in an effort to avoid duplicating the `test/utils/e2e.ts` file that contains setup functions for the local bundler setup that gets deployed from the `safe-4337-local-bundler` package. --- .github/workflows/certora_4337.yml | 8 +- examples/4337-gas-metering/package.json | 3 +- modules/4337/package.json | 11 +- modules/4337/src/utils/safe.ts | 60 +- modules/4337/src/utils/userOp.ts | 21 +- modules/4337/test/e2e/4337NestedSafe.spec.ts | 4 +- modules/4337/test/e2e/LocalBundler.spec.ts | 2 +- .../4337/test/e2e/SingletonSigners.spec.ts | 3 +- modules/4337/test/e2e/UniqueSigner.spec.ts | 2 +- modules/4337/test/e2e/WebAuthnSigner.spec.ts | 2 +- .../test/e2e/WebAuthnSingletonSigner.spec.ts | 3 +- modules/4337/test/utils/encoding.ts | 16 + modules/allowances/package.json | 1 - modules/passkey/package.json | 9 +- .../passkey/test/4337/WebAuthnSigner.spec.ts | 9 +- modules/passkey/test/utils/e2e.ts | 56 - modules/passkey/test/utils/encoding.ts | 5 - .../test/{ => webauthn}/WebAuthnShim.spec.ts | 2 +- package-lock.json | 992 ++++++++---------- package.json | 5 +- packages/4337-local-bundler/package.json | 9 +- packages/4337-local-bundler/src/index.ts | 4 +- .../4337-local-bundler/src/testing.ts | 33 +- .../4337-local-bundler/src/types/hardhat.ts | 2 + packages/4337-provider/.eslintignore | 1 + packages/4337-provider/.gitignore | 1 + packages/4337-provider/README.md | 3 + packages/4337-provider/package.json | 16 + packages/4337-provider/src/index.ts | 74 ++ packages/4337-provider/tsconfig.json | 13 + 30 files changed, 610 insertions(+), 760 deletions(-) delete mode 100644 modules/passkey/test/utils/e2e.ts delete mode 100644 modules/passkey/test/utils/encoding.ts rename modules/passkey/test/{ => webauthn}/WebAuthnShim.spec.ts (98%) rename modules/4337/test/utils/e2e.ts => packages/4337-local-bundler/src/testing.ts (68%) create mode 100644 packages/4337-local-bundler/src/types/hardhat.ts create mode 100644 packages/4337-provider/.eslintignore create mode 100644 packages/4337-provider/.gitignore create mode 100644 packages/4337-provider/README.md create mode 100644 packages/4337-provider/package.json create mode 100644 packages/4337-provider/src/index.ts create mode 100644 packages/4337-provider/tsconfig.json diff --git a/.github/workflows/certora_4337.yml b/.github/workflows/certora_4337.yml index 349917c2..cb6f1c01 100644 --- a/.github/workflows/certora_4337.yml +++ b/.github/workflows/certora_4337.yml @@ -20,9 +20,6 @@ jobs: strategy: matrix: rule: ['verify4337Module.sh', 'verifyTransactionExecutionMethods.sh', 'verifyValidationData.sh'] - defaults: - run: - working-directory: ./modules/4337 steps: - uses: actions/checkout@v3 @@ -30,10 +27,6 @@ jobs: uses: actions/setup-python@v4 with: { python-version: 3.11 } - - name: Install java - uses: actions/setup-java@v3 - with: { java-version: '17', java-package: jre, distribution: semeru } - - name: Install certora cli run: pip install -Iv certora-cli==6.1.3 @@ -47,6 +40,7 @@ jobs: run: npm ci - name: Verify rule ${{ matrix.rule }} + working-directory: ./modules/4337 run: | echo "key length" ${#CERTORAKEY} chmod +x ./certora/scripts/${{ matrix.rule }} diff --git a/examples/4337-gas-metering/package.json b/examples/4337-gas-metering/package.json index 822429fe..92733737 100644 --- a/examples/4337-gas-metering/package.json +++ b/examples/4337-gas-metering/package.json @@ -16,7 +16,7 @@ "alchemy:erc721": "tsx ./alchemy/alchemy.ts erc721", "alchemy:erc721:paymaster": "tsx ./alchemy/alchemy.ts erc721 paymaster=true", "alchemy": "tsx ./alchemy/alchemy.ts", - "build": "npx rimraf dist && tsc", + "build": "rimraf dist && tsc", "fmt": "prettier --ignore-path .gitignore --write .", "fmt:check": "prettier --check .", "lint": "eslint ./alchemy && eslint ./gelato && eslint ./pimlico && eslint ./utils", @@ -60,7 +60,6 @@ }, "devDependencies": { "@types/node": "20.11.18", - "rimraf": "^5.0.5", "tsx": "4.7.1", "typescript": "^5.3.3" } diff --git a/modules/4337/package.json b/modules/4337/package.json index c0283062..cec30279 100644 --- a/modules/4337/package.json +++ b/modules/4337/package.json @@ -15,8 +15,8 @@ ], "scripts": { "build": "npm run build:sol && npm run build:ts", - "build:ts": "npx rimraf dist && tsc", - "build:sol": "npx rimraf build && hardhat compile", + "build:ts": "rimraf dist && tsc", + "build:sol": "rimraf build typechain-types && hardhat compile", "test": "hardhat test --deploy-fixture", "test:4337": "4337-local-bundler-test", "test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test", @@ -31,9 +31,7 @@ "lint:ts": "eslint ./src --fix && eslint ./test --fix", "fmt": "prettier --write ./contracts/**/*.sol", "fmt:check": "prettier --check ./**/*.sol", - "prepack": "npm run build", - "prepublish": "npm run build", - "postinstall": "npm run build" + "prepare": "npm run build" }, "repository": { "type": "git", @@ -55,6 +53,7 @@ "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@openzeppelin/contracts": "^5.0.2", "@safe-global/safe-4337-local-bundler": "^0.0.0", + "@safe-global/safe-4337-provider": "^0.0.0", "@simplewebauthn/server": "9.0.0", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", @@ -75,7 +74,7 @@ }, "overrides": { "@safe-global/safe-contracts": { - "ethers": "^6.11.0" + "ethers": "^6.11.1" } }, "dependencies": { diff --git a/modules/4337/src/utils/safe.ts b/modules/4337/src/utils/safe.ts index b6d0fed1..ae0bd55b 100644 --- a/modules/4337/src/utils/safe.ts +++ b/modules/4337/src/utils/safe.ts @@ -1,9 +1,12 @@ -import { AddressLike, JsonRpcProvider, Provider, Signer, ethers } from 'ethers' +import { MultiProvider4337, RpcProvider } from '@safe-global/safe-4337-provider' +import { Provider, Signer, ethers } from 'ethers' // Import from Safe contracts repo once it is upgraded to ethers v6 and can be installed via npm import { MetaTransaction, SafeSignature, SignedSafeTransaction, buildSignatureBytes } from './execution' import { PackedUserOperation, UserOperation, EIP712_SAFE_OPERATION_TYPE, packGasParameters, unpackUserOperation } from './userOp' +export { MultiProvider4337 } + const AddressOne = '0x0000000000000000000000000000000000000001' const INTERFACES = new ethers.Interface([ @@ -91,61 +94,6 @@ const actionCalldata = (action: MetaTransaction): string => { return INTERFACES.encodeFunctionData('executeUserOp', [action.to, action.value, action.data, action.operation]) } -export interface RpcProvider extends Provider { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - send(method: string, params: unknown[]): Promise -} - -export class MultiProvider4337 extends JsonRpcProvider { - generalProvider: RpcProvider - constructor(aaProviderUrl: string, generalProvider: RpcProvider) { - super(aaProviderUrl) - this.generalProvider = generalProvider - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - send(method: string, params: unknown[]): Promise { - if ( - [ - 'eth_supportedEntryPoints', - 'eth_estimateUserOperationGas', - 'eth_sendUserOperation', - 'eth_getUserOperationByHash', - 'eth_getUserOperationReceipt', - ].indexOf(method) >= 0 - ) { - return super.send(method, params) - } else { - return this.generalProvider.send(method, params) - } - } - - public async sendUserOperation(userOp: UserOperation, entryPoint: AddressLike): Promise { - const jsonUserOp = { - sender: ethers.getAddress(userOp.sender), - nonce: ethers.toBeHex(userOp.nonce), - callData: ethers.hexlify(userOp.callData), - callGasLimit: ethers.toBeHex(userOp.callGasLimit), - verificationGasLimit: ethers.toBeHex(userOp.verificationGasLimit), - preVerificationGas: ethers.toBeHex(userOp.preVerificationGas), - maxFeePerGas: ethers.toBeHex(userOp.maxFeePerGas), - maxPriorityFeePerGas: ethers.toBeHex(userOp.maxPriorityFeePerGas), - signature: ethers.hexlify(userOp.signature), - } as Record - if (userOp.factory) { - jsonUserOp.factory = ethers.getAddress(userOp.factory) - jsonUserOp.factoryData = ethers.hexlify(userOp.factoryData!) - } - if (userOp.paymaster) { - jsonUserOp.paymaster = ethers.getAddress(userOp.paymaster) - jsonUserOp.paymasterVerificationGasLimit = ethers.toBeHex(userOp.paymasterVerificationGasLimit!) - jsonUserOp.paymasterPostOpGasLimit = ethers.toBeHex(userOp.paymasterPostOpGasLimit!) - jsonUserOp.paymasterData = ethers.hexlify(userOp.paymasterData!) - } - return await super.send('eth_sendUserOperation', [jsonUserOp, await ethers.resolveAddress(entryPoint, this)]) - } -} - export class Safe4337Operation { private safe: Safe4337 private action: MetaTransaction diff --git a/modules/4337/src/utils/userOp.ts b/modules/4337/src/utils/userOp.ts index d2c7f1cf..f9a16ccd 100644 --- a/modules/4337/src/utils/userOp.ts +++ b/modules/4337/src/utils/userOp.ts @@ -1,8 +1,9 @@ +import { UserOperation } from '@safe-global/safe-4337-provider' import { BigNumberish, BytesLike, Contract, Signer, ethers } from 'ethers' import { PackedUserOperationStruct as PackedUserOperation } from '../../typechain-types/contracts/Safe4337Module' import { SafeSignature } from './execution' -export { PackedUserOperation } +export { PackedUserOperation, UserOperation } type OptionalExceptFor = Partial>> & Required> @@ -15,24 +16,6 @@ export type SafeUserOperation = { } & GasParameters & Omit -export type UserOperation = { - sender: string - nonce: BigNumberish - factory?: string - factoryData?: BytesLike - callData: BytesLike - callGasLimit: BigNumberish - verificationGasLimit: BigNumberish - preVerificationGas: BigNumberish - maxFeePerGas: BigNumberish - maxPriorityFeePerGas: BigNumberish - paymaster?: string - paymasterVerificationGasLimit?: BigNumberish - paymasterPostOpGasLimit?: BigNumberish - paymasterData?: BytesLike - signature: BytesLike -} - export const EIP712_SAFE_OPERATION_TYPE = { SafeOp: [ { type: 'address', name: 'safe' }, diff --git a/modules/4337/test/e2e/4337NestedSafe.spec.ts b/modules/4337/test/e2e/4337NestedSafe.spec.ts index 449068ba..b9b738e1 100644 --- a/modules/4337/test/e2e/4337NestedSafe.spec.ts +++ b/modules/4337/test/e2e/4337NestedSafe.spec.ts @@ -1,3 +1,4 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { @@ -20,7 +21,6 @@ import { } from '../../src/utils/userOp' import { chainId } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' -import { BUNDLER_MNEMONIC, bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' import { BigNumberish, Signer } from 'ethers' import { assert } from 'console' @@ -299,7 +299,7 @@ describe('Nested Safes With An Execution Initiated by a Leaf 4337 Safe [@4337]', const setupTests = async () => { const { SafeModuleSetup, EntryPoint, HariWillibaldToken, Safe4337Module, SafeL2, SafeProxyFactory } = await deployments.run() - const [user, user2, user3] = await prepareAccounts(BUNDLER_MNEMONIC, 3) + const [user, user2, user3] = await prepareAccounts({ count: 3 }) const bundler = bundlerRpc() const entryPoint = new ethers.Contract(EntryPoint.address, EntryPoint.abi, ethers.provider) diff --git a/modules/4337/test/e2e/LocalBundler.spec.ts b/modules/4337/test/e2e/LocalBundler.spec.ts index 7c7bdd15..87cad010 100644 --- a/modules/4337/test/e2e/LocalBundler.spec.ts +++ b/modules/4337/test/e2e/LocalBundler.spec.ts @@ -1,10 +1,10 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { buildSignatureBytes } from '../../src/utils/execution' import { buildRpcUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, signSafeOp } from '../../src/utils/userOp' import { chainId, timestamp } from '../utils/encoding' import { Safe4337 } from '../../src/utils/safe' -import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' describe('Local Bundler [@4337]', () => { before(function () { diff --git a/modules/4337/test/e2e/SingletonSigners.spec.ts b/modules/4337/test/e2e/SingletonSigners.spec.ts index d7b97791..803c2e7d 100644 --- a/modules/4337/test/e2e/SingletonSigners.spec.ts +++ b/modules/4337/test/e2e/SingletonSigners.spec.ts @@ -1,3 +1,4 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { buildSignatureBytes } from '../../src/utils/execution' @@ -6,7 +7,7 @@ import { buildRpcUserOperationFromSafeUserOperation, buildSafeUserOpTransaction, } from '../../src/utils/userOp' -import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e' +import { encodeMultiSendTransactions } from '../utils/encoding' describe('Singleton Signers [@4337]', () => { before(function () { diff --git a/modules/4337/test/e2e/UniqueSigner.spec.ts b/modules/4337/test/e2e/UniqueSigner.spec.ts index dc923ded..7b62e05d 100644 --- a/modules/4337/test/e2e/UniqueSigner.spec.ts +++ b/modules/4337/test/e2e/UniqueSigner.spec.ts @@ -1,6 +1,6 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' -import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' import { chainId } from '../utils/encoding' import { packGasParameters, unpackUserOperation } from '../../src/utils/userOp' diff --git a/modules/4337/test/e2e/WebAuthnSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSigner.spec.ts index bdb51052..b70edd51 100644 --- a/modules/4337/test/e2e/WebAuthnSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSigner.spec.ts @@ -1,6 +1,6 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' -import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' import { chainId } from '../utils/encoding' import { UserVerificationRequirement, diff --git a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts index 50eb3d40..68821255 100644 --- a/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts +++ b/modules/4337/test/e2e/WebAuthnSingletonSigner.spec.ts @@ -1,6 +1,7 @@ +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' -import { bundlerRpc, encodeMultiSendTransactions, prepareAccounts, waitForUserOp } from '../utils/e2e' +import { encodeMultiSendTransactions } from '../utils/encoding' import { UserVerificationRequirement, WebAuthnCredentials, diff --git a/modules/4337/test/utils/encoding.ts b/modules/4337/test/utils/encoding.ts index 049e0971..a1e60263 100644 --- a/modules/4337/test/utils/encoding.ts +++ b/modules/4337/test/utils/encoding.ts @@ -1,3 +1,4 @@ +import { AddressLike, BigNumberish, BytesLike } from 'ethers' import { ethers } from 'hardhat' export const Erc20 = [ @@ -25,3 +26,18 @@ export const timestamp = async () => { } return block.timestamp } + +export interface MultiSendTransaction { + op: 0 | 1 + to: AddressLike + value?: BigNumberish + data: BytesLike +} + +export function encodeMultiSendTransactions(transactions: MultiSendTransaction[]) { + return ethers.concat( + transactions.map(({ op, to, value, data }) => + ethers.solidityPacked(['uint8', 'address', 'uint256', 'uint256', 'bytes'], [op, to, value ?? 0, ethers.dataLength(data), data]), + ), + ) +} diff --git a/modules/allowances/package.json b/modules/allowances/package.json index e35e9361..c61c1b11 100644 --- a/modules/allowances/package.json +++ b/modules/allowances/package.json @@ -45,7 +45,6 @@ "hardhat": "^2.21.0", "hardhat-deploy": "^0.12.1", "hardhat-gas-reporter": "^1.0.10", - "rimraf": "^5.0.5", "solhint": "4.1.1", "solidity-coverage": "^0.8.7", "ts-node": "^10.9.2", diff --git a/modules/passkey/package.json b/modules/passkey/package.json index 7eb510bc..3c4148c7 100644 --- a/modules/passkey/package.json +++ b/modules/passkey/package.json @@ -28,8 +28,8 @@ ], "scripts": { "build": "npm run build:sol && npm run build:ts", - "build:sol": "npx rimraf build && hardhat compile", - "build:ts": "npx rimraf dist && tsc", + "build:sol": "rimraf build typechain-types && hardhat compile", + "build:ts": "rimraf dist && tsc", "coverage": "hardhat coverage", "fmt": "prettier --write .", "fmt:check": "prettier --check .", @@ -38,7 +38,8 @@ "lint:ts": "eslint .", "test": "hardhat test", "test:4337": "4337-local-bundler-test", - "test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test" + "test:4337:upstream": "USE_UPSTREAM_BUNDLER=1 4337-local-bundler-test", + "prepare": "npm run build -w ../4337 && npm run build" }, "devDependencies": { "@account-abstraction/contracts": "^0.7.0", @@ -55,7 +56,7 @@ }, "overrides": { "@safe-global/safe-contracts": { - "ethers": "^6.11.0" + "ethers": "^6.11.1" } }, "dependencies": { diff --git a/modules/passkey/test/4337/WebAuthnSigner.spec.ts b/modules/passkey/test/4337/WebAuthnSigner.spec.ts index 0ce600fe..a236fc79 100644 --- a/modules/passkey/test/4337/WebAuthnSigner.spec.ts +++ b/modules/passkey/test/4337/WebAuthnSigner.spec.ts @@ -1,8 +1,7 @@ import { expect } from 'chai' import { deployments, ethers, network } from 'hardhat' import { packGasParameters, unpackUserOperation } from '@safe-global/safe-4337/dist/src/utils/userOp' -import { bundlerRpc, prepareAccounts, waitForUserOp } from '../utils/e2e' -import { chainId } from '../utils/encoding' +import { bundlerRpc, prepareAccounts, waitForUserOp } from '@safe-global/safe-4337-local-bundler' import { WebAuthnCredentials, decodePublicKey, encodeWebAuthnSignature } from '../utils/webauthn' describe('WebAuthn Signers [@4337]', () => { @@ -64,6 +63,8 @@ describe('WebAuthn Signers [@4337]', () => { webAuthnVerifier, SafeL2, } = await setupTests() + + const { chainId } = await ethers.provider.getNetwork() const webAuthnVerifierAddress = await webAuthnVerifier.getAddress() const credential = navigator.credentials.create({ @@ -95,7 +96,7 @@ describe('WebAuthn Signers [@4337]', () => { fallbackHandler: module.target, } const safeInitHash = ethers.TypedDataEncoder.hash( - { verifyingContract: await signerLaunchpad.getAddress(), chainId: await chainId() }, + { verifyingContract: await signerLaunchpad.getAddress(), chainId }, { SafeInit: [ { type: 'address', name: 'singleton' }, @@ -171,7 +172,7 @@ describe('WebAuthn Signers [@4337]', () => { entryPoint: entryPoint.target, } const safeInitOpHash = ethers.TypedDataEncoder.hash( - { verifyingContract: await signerLaunchpad.getAddress(), chainId: await chainId() }, + { verifyingContract: await signerLaunchpad.getAddress(), chainId }, { SafeInitOp: [ { type: 'bytes32', name: 'userOpHash' }, diff --git a/modules/passkey/test/utils/e2e.ts b/modules/passkey/test/utils/e2e.ts deleted file mode 100644 index 8906b9d6..00000000 --- a/modules/passkey/test/utils/e2e.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { deployments, ethers } from 'hardhat' -import { MultiProvider4337 } from '@safe-global/safe-4337/dist/src/utils/safe' -import { AddressLike, BigNumberish, BytesLike, HDNodeWallet } from 'ethers' -import { PackedUserOperationStruct } from '../../typechain-types/@account-abstraction/contracts/interfaces/IAccount' - -export const BUNDLER_URL = process.env.TEST_BUNLDER_URL || 'http://localhost:3000/rpc' -export const BUNDLER_MNEMONIC = process.env.TEST_BUNDLER_MNEMONIC || 'test test test test test test test test test test test junk' - -export async function prepareAccounts(mnemonic = BUNDLER_MNEMONIC, count = 1): Promise { - const bundler = ethers.HDNodeWallet.fromPhrase(mnemonic).connect(ethers.provider) - const accounts = [...Array(count)].map(() => ethers.Wallet.createRandom(ethers.provider)) - - const [deployer] = await ethers.getSigners() - const fund = ethers.parseEther('1.337') - for (const account of [bundler, ...accounts]) { - const balance = await ethers.provider.getBalance(account.address) - if (balance < fund) { - const transaction = await deployer.sendTransaction({ to: account.address, value: fund }) - await transaction.wait() - } - } - - return accounts -} - -export function bundlerRpc(url = BUNDLER_URL) { - return new MultiProvider4337(url, ethers.provider) -} - -export async function waitForUserOp({ sender, nonce }: Pick, timeout = 10_000) { - const { address: entryPointAddress } = await deployments.get('EntryPoint') - const entryPoint = await ethers.getContractAt('INonceManager', entryPointAddress) - const start = performance.now() - const key = BigInt(nonce) >> 64n - while ((await entryPoint.getNonce(sender, key)) <= BigInt(nonce)) { - if (performance.now() - start > timeout) { - throw new Error(`timeout waiting for user operation execution`) - } - await new Promise((resolve) => setTimeout(resolve, 10)) - } -} - -export interface MultiSendTransaction { - op: 0 | 1 - to: AddressLike - value?: BigNumberish - data: BytesLike -} - -export function encodeMultiSendTransactions(transactions: MultiSendTransaction[]) { - return ethers.concat( - transactions.map(({ op, to, value, data }) => - ethers.solidityPacked(['uint8', 'address', 'uint256', 'uint256', 'bytes'], [op, to, value ?? 0, ethers.dataLength(data), data]), - ), - ) -} diff --git a/modules/passkey/test/utils/encoding.ts b/modules/passkey/test/utils/encoding.ts deleted file mode 100644 index fde9528d..00000000 --- a/modules/passkey/test/utils/encoding.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ethers } from 'hardhat' - -export async function chainId(): Promise { - return (await ethers.provider.getNetwork()).chainId -} diff --git a/modules/passkey/test/WebAuthnShim.spec.ts b/modules/passkey/test/webauthn/WebAuthnShim.spec.ts similarity index 98% rename from modules/passkey/test/WebAuthnShim.spec.ts rename to modules/passkey/test/webauthn/WebAuthnShim.spec.ts index 2d068d6c..1ac405dd 100644 --- a/modules/passkey/test/WebAuthnShim.spec.ts +++ b/modules/passkey/test/webauthn/WebAuthnShim.spec.ts @@ -11,7 +11,7 @@ import { import { expect } from 'chai' import CBOR from 'cbor' import { ethers } from 'ethers' -import { WebAuthnCredentials, base64UrlEncode } from './utils/webauthn' +import { WebAuthnCredentials, base64UrlEncode } from '../utils/webauthn' describe('WebAuthn Shim', () => { const navigator = { diff --git a/package-lock.json b/package-lock.json index a26ac5fe..0b0fe11f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,11 @@ "": { "name": "@safe-global/safe-modules", "version": "1.0.0", + "hasInstallScript": true, "license": "GPL-3.0", "workspaces": [ - "modules/*", "packages/*", + "modules/*", "examples/*" ], "devDependencies": { @@ -24,7 +25,8 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", "prettier": "^3.2.5", - "prettier-plugin-solidity": "^1.3.1" + "prettier-plugin-solidity": "^1.3.1", + "rimraf": "^5.0.5" } }, "examples/4337-gas-metering": { @@ -42,7 +44,6 @@ }, "devDependencies": { "@types/node": "20.11.18", - "rimraf": "^5.0.5", "tsx": "4.7.1", "typescript": "^5.3.3" } @@ -109,49 +110,6 @@ } } }, - "examples/4337-gas-metering/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "examples/4337-gas-metering/node_modules/glob": { - "version": "10.3.10", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "examples/4337-gas-metering/node_modules/minimatch": { - "version": "9.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "examples/4337-gas-metering/node_modules/permissionless": { "version": "0.0.35", "license": "MIT", @@ -159,23 +117,6 @@ "viem": "^2.0.0" } }, - "examples/4337-gas-metering/node_modules/rimraf": { - "version": "5.0.5", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "examples/4337-gas-metering/node_modules/viem": { "version": "2.7.9", "funding": [ @@ -558,7 +499,6 @@ "modules/4337": { "name": "@safe-global/safe-4337", "version": "0.3.0", - "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { "@safe-global/safe-contracts": "^1.4.1-build.0" @@ -569,6 +509,7 @@ "@nomicfoundation/hardhat-toolbox": "^4.0.0", "@openzeppelin/contracts": "^5.0.2", "@safe-global/safe-4337-local-bundler": "^0.0.0", + "@safe-global/safe-4337-provider": "^0.0.0", "@simplewebauthn/server": "9.0.0", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", @@ -912,7 +853,6 @@ "hardhat": "^2.21.0", "hardhat-deploy": "^0.12.1", "hardhat-gas-reporter": "^1.0.10", - "rimraf": "^5.0.5", "solhint": "4.1.1", "solidity-coverage": "^0.8.7", "ts-node": "^10.9.2", @@ -1029,14 +969,6 @@ "typechain": "^8.3.2" } }, - "modules/allowances/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "modules/allowances/node_modules/ethers": { "version": "6.11.1", "dev": true, @@ -1083,27 +1015,6 @@ "node": ">=10" } }, - "modules/allowances/node_modules/glob": { - "version": "10.3.10", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "modules/allowances/node_modules/jsonfile": { "version": "6.1.0", "dev": true, @@ -1115,37 +1026,6 @@ "graceful-fs": "^4.1.6" } }, - "modules/allowances/node_modules/minimatch": { - "version": "9.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "modules/allowances/node_modules/rimraf": { - "version": "5.0.5", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "modules/allowances/node_modules/tslib": { "version": "2.4.0", "dev": true, @@ -1545,7 +1425,6 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -2434,7 +2313,6 @@ }, "node_modules/@fastify/busboy": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -2481,8 +2359,9 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2497,8 +2376,9 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2508,8 +2388,9 @@ }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2519,13 +2400,15 @@ }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2540,8 +2423,9 @@ }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2554,8 +2438,9 @@ }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2570,7 +2455,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2582,7 +2466,6 @@ }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -2619,7 +2502,6 @@ }, "node_modules/@metamask/eth-sig-util": { "version": "4.0.1", - "dev": true, "license": "ISC", "dependencies": { "ethereumjs-abi": "^0.6.8", @@ -2917,7 +2799,6 @@ }, "node_modules/@noble/hashes": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "individual", @@ -2928,7 +2809,6 @@ }, "node_modules/@noble/secp256k1": { "version": "1.7.1", - "dev": true, "funding": [ { "type": "individual", @@ -2939,7 +2819,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2951,7 +2830,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2959,7 +2837,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2971,7 +2848,6 @@ }, "node_modules/@nomicfoundation/edr": { "version": "0.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 18" @@ -2993,7 +2869,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3008,7 +2883,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3020,7 +2894,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-common": { "version": "4.0.4", - "dev": true, "license": "MIT", "dependencies": { "@nomicfoundation/ethereumjs-util": "9.0.4" @@ -3028,7 +2901,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-rlp": { "version": "5.0.4", - "dev": true, "license": "MPL-2.0", "bin": { "rlp": "bin/rlp.cjs" @@ -3039,7 +2911,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-tx": { "version": "5.0.4", - "dev": true, "license": "MPL-2.0", "dependencies": { "@nomicfoundation/ethereumjs-common": "4.0.4", @@ -3061,7 +2932,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { "version": "0.1.3", - "dev": true, "license": "MIT", "dependencies": { "@types/pbkdf2": "^3.0.0", @@ -3083,7 +2953,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-util": { "version": "9.0.4", - "dev": true, "license": "MPL-2.0", "dependencies": { "@nomicfoundation/ethereumjs-rlp": "5.0.4", @@ -3103,7 +2972,6 @@ }, "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { "version": "0.1.3", - "dev": true, "license": "MIT", "dependencies": { "@types/pbkdf2": "^3.0.0", @@ -3125,7 +2993,6 @@ }, "node_modules/@nomicfoundation/hardhat-network-helpers": { "version": "1.0.10", - "dev": true, "license": "MIT", "dependencies": { "ethereumjs-util": "^7.1.4" @@ -3136,7 +3003,6 @@ }, "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereum-cryptography": { "version": "0.1.3", - "dev": true, "license": "MIT", "dependencies": { "@types/pbkdf2": "^3.0.0", @@ -3158,7 +3024,6 @@ }, "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereumjs-util": { "version": "7.1.5", - "dev": true, "license": "MPL-2.0", "dependencies": { "@types/bn.js": "^5.1.0", @@ -3173,7 +3038,6 @@ }, "node_modules/@nomicfoundation/hardhat-verify": { "version": "2.0.4", - "dev": true, "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -3192,7 +3056,6 @@ }, "node_modules/@nomicfoundation/hardhat-verify/node_modules/cbor": { "version": "8.1.0", - "dev": true, "license": "MIT", "dependencies": { "nofilter": "^3.1.0" @@ -3203,7 +3066,6 @@ }, "node_modules/@nomicfoundation/solidity-analyzer": { "version": "0.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -3226,7 +3088,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3241,7 +3102,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3445,8 +3305,9 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -3532,6 +3393,10 @@ "resolved": "packages/4337-local-bundler", "link": true }, + "node_modules/@safe-global/safe-4337-provider": { + "resolved": "packages/4337-provider", + "link": true + }, "node_modules/@safe-global/safe-allowance-module": { "resolved": "modules/allowances", "link": true @@ -3602,7 +3467,6 @@ }, "node_modules/@scure/bip32": { "version": "1.1.5", - "dev": true, "funding": [ { "type": "individual", @@ -3618,7 +3482,6 @@ }, "node_modules/@scure/bip39": { "version": "1.1.1", - "dev": true, "funding": [ { "type": "individual", @@ -3633,7 +3496,6 @@ }, "node_modules/@sentry/core": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sentry/hub": "5.30.0", @@ -3648,7 +3510,6 @@ }, "node_modules/@sentry/hub": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sentry/types": "5.30.0", @@ -3661,7 +3522,6 @@ }, "node_modules/@sentry/minimal": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sentry/hub": "5.30.0", @@ -3674,7 +3534,6 @@ }, "node_modules/@sentry/node": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sentry/core": "5.30.0", @@ -3693,7 +3552,6 @@ }, "node_modules/@sentry/tracing": { "version": "5.30.0", - "dev": true, "license": "MIT", "dependencies": { "@sentry/hub": "5.30.0", @@ -3708,7 +3566,6 @@ }, "node_modules/@sentry/types": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=6" @@ -3716,7 +3573,6 @@ }, "node_modules/@sentry/utils": { "version": "5.30.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sentry/types": "5.30.0", @@ -3764,7 +3620,6 @@ }, "node_modules/@solidity-parser/parser": { "version": "0.14.5", - "dev": true, "license": "MIT", "dependencies": { "antlr4ts": "^0.5.0-alpha.4" @@ -3900,7 +3755,7 @@ }, "node_modules/@swc/core": { "version": "1.4.1", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -3967,12 +3822,12 @@ }, "node_modules/@swc/counter": { "version": "0.1.2", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@swc/types": { "version": "0.1.5", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@szmarczak/http-timer": { @@ -3988,27 +3843,22 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.9", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", - "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", - "dev": true, "license": "MIT" }, "node_modules/@types/bn.js": { "version": "5.1.5", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4016,12 +3866,10 @@ }, "node_modules/@types/chai": { "version": "4.3.11", - "dev": true, "license": "MIT" }, "node_modules/@types/chai-as-promised": { "version": "7.1.8", - "dev": true, "license": "MIT", "dependencies": { "@types/chai": "*" @@ -4029,7 +3877,6 @@ }, "node_modules/@types/concat-stream": { "version": "1.6.1", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4049,7 +3896,6 @@ }, "node_modules/@types/form-data": { "version": "0.0.33", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4057,7 +3903,6 @@ }, "node_modules/@types/glob": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "@types/minimatch": "*", @@ -4081,17 +3926,14 @@ }, "node_modules/@types/lru-cache": { "version": "5.1.1", - "dev": true, "license": "MIT" }, "node_modules/@types/minimatch": { "version": "5.1.2", - "dev": true, "license": "MIT" }, "node_modules/@types/mocha": { "version": "10.0.6", - "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -4100,7 +3942,6 @@ }, "node_modules/@types/node": { "version": "20.11.18", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~5.26.4" @@ -4108,7 +3949,6 @@ }, "node_modules/@types/pbkdf2": { "version": "3.1.2", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4116,7 +3956,6 @@ }, "node_modules/@types/prettier": { "version": "2.7.3", - "dev": true, "license": "MIT" }, "node_modules/@types/prop-types": { @@ -4153,7 +3992,6 @@ }, "node_modules/@types/secp256k1": { "version": "4.0.6", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -4880,7 +4718,6 @@ }, "node_modules/abbrev": { "version": "1.0.9", - "dev": true, "license": "ISC" }, "node_modules/abitype": { @@ -4916,7 +4753,6 @@ }, "node_modules/acorn-walk": { "version": "8.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -4924,7 +4760,6 @@ }, "node_modules/adm-zip": { "version": "0.4.16", - "dev": true, "license": "MIT", "engines": { "node": ">=0.3.0" @@ -4936,7 +4771,6 @@ }, "node_modules/agent-base": { "version": "6.0.2", - "dev": true, "license": "MIT", "dependencies": { "debug": "4" @@ -4947,7 +4781,6 @@ }, "node_modules/aggregate-error": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", @@ -5179,7 +5012,6 @@ }, "node_modules/amdefine": { "version": "1.0.1", - "dev": true, "license": "BSD-3-Clause OR MIT", "optional": true, "peer": true, @@ -5189,7 +5021,6 @@ }, "node_modules/ansi-align": { "version": "3.0.1", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.1.0" @@ -5204,7 +5035,6 @@ }, "node_modules/ansi-escapes": { "version": "4.3.2", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -5225,7 +5055,6 @@ }, "node_modules/ansi-styles": { "version": "3.2.1", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -5244,7 +5073,6 @@ }, "node_modules/antlr4ts": { "version": "0.5.0-alpha.4", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/anymatch": { @@ -5260,17 +5088,14 @@ }, "node_modules/arg": { "version": "4.1.3", - "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "dev": true, "license": "Python-2.0" }, "node_modules/array-back": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5308,7 +5133,6 @@ }, "node_modules/array-union": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5316,7 +5140,6 @@ }, "node_modules/array-uniq": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5396,7 +5219,6 @@ }, "node_modules/asap": { "version": "2.0.6", - "dev": true, "license": "MIT" }, "node_modules/asn1js": { @@ -5419,7 +5241,6 @@ }, "node_modules/assertion-error": { "version": "1.1.0", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -5432,7 +5253,6 @@ }, "node_modules/astral-regex": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5440,7 +5260,6 @@ }, "node_modules/async": { "version": "1.5.2", - "dev": true, "license": "MIT" }, "node_modules/async-mutex": { @@ -5460,7 +5279,6 @@ }, "node_modules/at-least-node": { "version": "1.0.0", - "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" @@ -5493,12 +5311,10 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "license": "MIT" }, "node_modules/base-x": { "version": "3.0.9", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.0.1" @@ -5540,7 +5356,6 @@ }, "node_modules/blakejs": { "version": "1.2.1", - "dev": true, "license": "MIT" }, "node_modules/bn.js": { @@ -5549,7 +5364,6 @@ }, "node_modules/boxen": { "version": "5.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-align": "^3.0.0", @@ -5570,7 +5384,6 @@ }, "node_modules/boxen/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5584,7 +5397,6 @@ }, "node_modules/boxen/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5599,7 +5411,6 @@ }, "node_modules/boxen/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5610,12 +5421,10 @@ }, "node_modules/boxen/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/boxen/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5623,7 +5432,6 @@ }, "node_modules/boxen/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5634,7 +5442,6 @@ }, "node_modules/boxen/node_modules/type-fest": { "version": "0.20.2", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -5645,7 +5452,6 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -5668,12 +5474,10 @@ }, "node_modules/browser-stdout": { "version": "1.3.1", - "dev": true, "license": "ISC" }, "node_modules/browserify-aes": { "version": "1.2.0", - "dev": true, "license": "MIT", "dependencies": { "buffer-xor": "^1.0.3", @@ -5686,7 +5490,6 @@ }, "node_modules/bs58": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "base-x": "^3.0.2" @@ -5694,7 +5497,6 @@ }, "node_modules/bs58check": { "version": "2.1.2", - "dev": true, "license": "MIT", "dependencies": { "bs58": "^4.0.0", @@ -5726,12 +5528,10 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, "license": "MIT" }, "node_modules/buffer-xor": { "version": "1.0.3", - "dev": true, "license": "MIT" }, "node_modules/bufferutil": { @@ -5747,7 +5547,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -5800,7 +5599,6 @@ }, "node_modules/camelcase": { "version": "6.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -5811,7 +5609,6 @@ }, "node_modules/caseless": { "version": "0.12.0", - "dev": true, "license": "Apache-2.0" }, "node_modules/cbor": { @@ -5856,7 +5653,6 @@ }, "node_modules/chai": { "version": "4.4.0", - "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^1.1.0", @@ -5873,7 +5669,6 @@ }, "node_modules/chai-as-promised": { "version": "7.1.1", - "dev": true, "license": "WTFPL", "dependencies": { "check-error": "^1.0.2" @@ -5884,7 +5679,6 @@ }, "node_modules/chalk": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -5897,7 +5691,6 @@ }, "node_modules/charenc": { "version": "0.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": "*" @@ -5905,7 +5698,6 @@ }, "node_modules/check-error": { "version": "1.0.3", - "dev": true, "license": "MIT", "dependencies": { "get-func-name": "^2.0.2" @@ -5941,12 +5733,10 @@ }, "node_modules/ci-info": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/cipher-base": { "version": "1.0.4", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.1", @@ -5962,7 +5752,6 @@ }, "node_modules/clean-stack": { "version": "2.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5970,7 +5759,6 @@ }, "node_modules/cli-boxes": { "version": "2.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5981,7 +5769,6 @@ }, "node_modules/cli-table3": { "version": "0.5.1", - "dev": true, "license": "MIT", "dependencies": { "object-assign": "^4.1.0", @@ -5996,7 +5783,6 @@ }, "node_modules/cli-table3/node_modules/ansi-regex": { "version": "3.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6004,7 +5790,6 @@ }, "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6012,7 +5797,6 @@ }, "node_modules/cli-table3/node_modules/string-width": { "version": "2.1.1", - "dev": true, "license": "MIT", "dependencies": { "is-fullwidth-code-point": "^2.0.0", @@ -6024,7 +5808,6 @@ }, "node_modules/cli-table3/node_modules/strip-ansi": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^3.0.0" @@ -6050,7 +5833,6 @@ }, "node_modules/cliui": { "version": "7.0.4", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -6074,7 +5856,6 @@ }, "node_modules/color-convert": { "version": "1.9.3", - "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -6082,12 +5863,10 @@ }, "node_modules/color-name": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.1.90" @@ -6105,12 +5884,10 @@ }, "node_modules/command-exists": { "version": "1.2.9", - "dev": true, "license": "MIT" }, "node_modules/command-line-args": { "version": "5.2.1", - "dev": true, "license": "MIT", "dependencies": { "array-back": "^3.1.0", @@ -6124,7 +5901,6 @@ }, "node_modules/command-line-usage": { "version": "6.1.3", - "dev": true, "license": "MIT", "dependencies": { "array-back": "^4.0.2", @@ -6138,7 +5914,6 @@ }, "node_modules/command-line-usage/node_modules/array-back": { "version": "4.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6146,7 +5921,6 @@ }, "node_modules/command-line-usage/node_modules/typical": { "version": "5.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -6154,17 +5928,14 @@ }, "node_modules/commander": { "version": "3.0.2", - "dev": true, "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", - "dev": true, "license": "MIT" }, "node_modules/concat-stream": { "version": "1.6.2", - "dev": true, "engines": [ "node >= 0.8" ], @@ -6178,12 +5949,10 @@ }, "node_modules/concat-stream/node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/concat-stream/node_modules/readable-stream": { "version": "2.3.8", - "dev": true, "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -6197,7 +5966,6 @@ }, "node_modules/concat-stream/node_modules/string_decoder": { "version": "1.1.1", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -6221,7 +5989,6 @@ }, "node_modules/cookie": { "version": "0.4.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -6233,7 +6000,6 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "dev": true, "license": "MIT" }, "node_modules/cosmiconfig": { @@ -6273,7 +6039,6 @@ }, "node_modules/create-hash": { "version": "1.2.0", - "dev": true, "license": "MIT", "dependencies": { "cipher-base": "^1.0.1", @@ -6285,7 +6050,6 @@ }, "node_modules/create-hmac": { "version": "1.1.7", - "dev": true, "license": "MIT", "dependencies": { "cipher-base": "^1.0.3", @@ -6298,7 +6062,6 @@ }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, "license": "MIT" }, "node_modules/cross-fetch": { @@ -6327,7 +6090,6 @@ }, "node_modules/crypt": { "version": "0.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": "*" @@ -6350,8 +6112,7 @@ "license": "MIT" }, "node_modules/death": { - "version": "1.1.0", - "dev": true + "version": "1.1.0" }, "node_modules/debug": { "version": "4.3.4", @@ -6370,7 +6131,6 @@ }, "node_modules/decamelize": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -6413,7 +6173,6 @@ }, "node_modules/deep-eql": { "version": "4.1.3", - "dev": true, "license": "MIT", "dependencies": { "type-detect": "^4.0.0" @@ -6424,7 +6183,6 @@ }, "node_modules/deep-extend": { "version": "0.6.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4.0.0" @@ -6432,7 +6190,6 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "dev": true, "license": "MIT" }, "node_modules/defer-to-connect": { @@ -6491,7 +6248,6 @@ }, "node_modules/depd": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -6516,7 +6272,6 @@ }, "node_modules/diff": { "version": "5.0.0", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -6524,7 +6279,6 @@ }, "node_modules/difflib": { "version": "0.2.4", - "dev": true, "dependencies": { "heap": ">= 0.2.0" } @@ -6535,7 +6289,6 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -6577,8 +6330,9 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true }, "node_modules/elliptic": { "version": "6.5.4", @@ -6635,7 +6389,6 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6808,7 +6561,6 @@ }, "node_modules/escalade": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6816,7 +6568,6 @@ }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -6824,7 +6575,6 @@ }, "node_modules/escodegen": { "version": "1.8.1", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^2.7.1", @@ -6845,14 +6595,12 @@ }, "node_modules/escodegen/node_modules/estraverse": { "version": "1.9.3", - "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/escodegen/node_modules/levn": { "version": "0.3.0", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2", @@ -6864,7 +6612,6 @@ }, "node_modules/escodegen/node_modules/optionator": { "version": "0.8.3", - "dev": true, "license": "MIT", "dependencies": { "deep-is": "~0.1.3", @@ -6880,14 +6627,12 @@ }, "node_modules/escodegen/node_modules/prelude-ls": { "version": "1.1.2", - "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/escodegen/node_modules/source-map": { "version": "0.2.0", - "dev": true, "optional": true, "peer": true, "dependencies": { @@ -6899,7 +6644,6 @@ }, "node_modules/escodegen/node_modules/type-check": { "version": "0.3.2", - "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "~1.1.2" @@ -7348,7 +7092,6 @@ }, "node_modules/esprima": { "version": "2.7.3", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -7394,7 +7137,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -7423,7 +7165,6 @@ }, "node_modules/eth-gas-reporter": { "version": "0.2.27", - "dev": true, "license": "MIT", "dependencies": { "@solidity-parser/parser": "^0.14.0", @@ -7451,7 +7192,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/contracts": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7478,7 +7218,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/hdnode": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7507,7 +7246,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/json-wallets": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7537,7 +7275,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/pbkdf2": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7556,7 +7293,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/solidity": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7579,7 +7315,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/units": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7599,7 +7334,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/wallet": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7631,7 +7365,6 @@ }, "node_modules/eth-gas-reporter/node_modules/@ethersproject/wordlists": { "version": "5.7.0", - "dev": true, "funding": [ { "type": "individual", @@ -7653,12 +7386,10 @@ }, "node_modules/eth-gas-reporter/node_modules/aes-js": { "version": "3.0.0", - "dev": true, "license": "MIT" }, "node_modules/eth-gas-reporter/node_modules/axios": { "version": "1.6.5", - "dev": true, "license": "MIT", "dependencies": { "follow-redirects": "^1.15.4", @@ -7668,7 +7399,6 @@ }, "node_modules/eth-gas-reporter/node_modules/ethers": { "version": "5.7.2", - "dev": true, "funding": [ { "type": "individual", @@ -7754,7 +7484,6 @@ }, "node_modules/ethereum-bloom-filters": { "version": "1.0.10", - "dev": true, "license": "MIT", "dependencies": { "js-sha3": "^0.8.0" @@ -7762,7 +7491,6 @@ }, "node_modules/ethereum-cryptography": { "version": "1.2.0", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "1.2.0", @@ -7773,7 +7501,6 @@ }, "node_modules/ethereumjs-abi": { "version": "0.6.8", - "dev": true, "license": "MIT", "dependencies": { "bn.js": "^4.11.8", @@ -7782,12 +7509,10 @@ }, "node_modules/ethereumjs-abi/node_modules/bn.js": { "version": "4.12.0", - "dev": true, "license": "MIT" }, "node_modules/ethereumjs-util": { "version": "6.2.1", - "dev": true, "license": "MPL-2.0", "dependencies": { "@types/bn.js": "^4.11.3", @@ -7801,7 +7526,6 @@ }, "node_modules/ethereumjs-util/node_modules/@types/bn.js": { "version": "4.11.6", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -7809,12 +7533,10 @@ }, "node_modules/ethereumjs-util/node_modules/bn.js": { "version": "4.12.0", - "dev": true, "license": "MIT" }, "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { "version": "0.1.3", - "dev": true, "license": "MIT", "dependencies": { "@types/pbkdf2": "^3.0.0", @@ -8380,7 +8102,6 @@ }, "node_modules/ethjs-unit": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "bn.js": "4.11.6", @@ -8393,12 +8114,10 @@ }, "node_modules/ethjs-unit/node_modules/bn.js": { "version": "4.11.6", - "dev": true, "license": "MIT" }, "node_modules/ethjs-util": { "version": "0.1.6", - "dev": true, "license": "MIT", "dependencies": { "is-hex-prefixed": "1.0.0", @@ -8430,7 +8149,6 @@ }, "node_modules/evp_bytestokey": { "version": "1.0.3", - "dev": true, "license": "MIT", "dependencies": { "md5.js": "^1.3.4", @@ -8481,7 +8199,6 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "dev": true, "license": "MIT" }, "node_modules/fast-diff": { @@ -8491,7 +8208,6 @@ }, "node_modules/fast-glob": { "version": "3.3.2", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -8511,7 +8227,6 @@ }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "dev": true, "license": "MIT" }, "node_modules/fast-redact": { @@ -8527,7 +8242,6 @@ }, "node_modules/fastq": { "version": "1.16.0", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -8563,7 +8277,6 @@ }, "node_modules/find-replace": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "array-back": "^3.0.1" @@ -8574,7 +8287,6 @@ }, "node_modules/find-up": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^2.0.0" @@ -8585,7 +8297,6 @@ }, "node_modules/flat": { "version": "5.0.2", - "dev": true, "license": "BSD-3-Clause", "bin": { "flat": "cli.js" @@ -8658,8 +8369,9 @@ }, "node_modules/foreground-child": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", "dev": true, - "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -8693,12 +8405,10 @@ }, "node_modules/fp-ts": { "version": "1.19.3", - "dev": true, "license": "MIT" }, "node_modules/fs-extra": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2", @@ -8711,12 +8421,10 @@ }, "node_modules/fs-readdir-recursive": { "version": "1.1.0", - "dev": true, "license": "MIT" }, "node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, "license": "ISC" }, "node_modules/function-bind": { @@ -8760,7 +8468,6 @@ }, "node_modules/get-func-name": { "version": "2.0.2", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -8781,7 +8488,6 @@ }, "node_modules/get-port": { "version": "3.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8830,7 +8536,6 @@ }, "node_modules/ghost-testrpc": { "version": "0.0.2", - "dev": true, "license": "ISC", "dependencies": { "chalk": "^2.4.2", @@ -8842,7 +8547,6 @@ }, "node_modules/glob": { "version": "7.2.0", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -8871,7 +8575,6 @@ }, "node_modules/global-modules": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "global-prefix": "^3.0.0" @@ -8882,7 +8585,6 @@ }, "node_modules/global-prefix": { "version": "3.0.0", - "dev": true, "license": "MIT", "dependencies": { "ini": "^1.3.5", @@ -8895,7 +8597,6 @@ }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9022,7 +8723,6 @@ }, "node_modules/handlebars": { "version": "4.7.8", - "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.5", @@ -9044,7 +8744,6 @@ "version": "2.21.0", "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.21.0.tgz", "integrity": "sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw==", - "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", @@ -9480,7 +9179,6 @@ }, "node_modules/hardhat-gas-reporter": { "version": "1.0.10", - "dev": true, "license": "MIT", "dependencies": { "array-uniq": "1.0.3", @@ -9501,7 +9199,6 @@ }, "node_modules/has-flag": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -9553,7 +9250,6 @@ }, "node_modules/hash-base": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.4", @@ -9566,7 +9262,6 @@ }, "node_modules/hash-base/node_modules/safe-buffer": { "version": "5.2.1", - "dev": true, "funding": [ { "type": "github", @@ -9603,7 +9298,6 @@ }, "node_modules/he": { "version": "1.2.0", - "dev": true, "license": "MIT", "bin": { "he": "bin/he" @@ -9611,7 +9305,6 @@ }, "node_modules/heap": { "version": "0.2.7", - "dev": true, "license": "MIT" }, "node_modules/hey-listen": { @@ -9629,7 +9322,6 @@ }, "node_modules/http-basic": { "version": "8.1.3", - "dev": true, "license": "MIT", "dependencies": { "caseless": "^0.12.0", @@ -9648,7 +9340,6 @@ }, "node_modules/http-errors": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "depd": "2.0.0", @@ -9663,7 +9354,6 @@ }, "node_modules/http-response-object": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "^10.0.3" @@ -9671,7 +9361,6 @@ }, "node_modules/http-response-object/node_modules/@types/node": { "version": "10.17.60", - "dev": true, "license": "MIT" }, "node_modules/http-shutdown": { @@ -9696,7 +9385,6 @@ }, "node_modules/https-proxy-agent": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "6", @@ -9729,7 +9417,6 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -9762,7 +9449,6 @@ }, "node_modules/ignore": { "version": "5.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -9770,7 +9456,6 @@ }, "node_modules/immutable": { "version": "4.3.4", - "dev": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -9805,7 +9490,6 @@ }, "node_modules/indent-string": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9813,7 +9497,6 @@ }, "node_modules/inflight": { "version": "1.0.6", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -9826,7 +9509,6 @@ }, "node_modules/ini": { "version": "1.3.8", - "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -9844,7 +9526,6 @@ }, "node_modules/interpret": { "version": "1.4.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.10" @@ -9852,7 +9533,6 @@ }, "node_modules/io-ts": { "version": "1.10.4", - "dev": true, "license": "MIT", "dependencies": { "fp-ts": "^1.0.0" @@ -10024,7 +9704,6 @@ }, "node_modules/is-hex-prefixed": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6.5.0", @@ -10089,7 +9768,6 @@ }, "node_modules/is-plain-obj": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10179,7 +9857,6 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10257,8 +9934,9 @@ }, "node_modules/jackspeak": { "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -10289,7 +9967,6 @@ }, "node_modules/js-yaml": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -10354,7 +10031,6 @@ }, "node_modules/jsonfile": { "version": "4.0.0", - "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" @@ -10362,7 +10038,6 @@ }, "node_modules/jsonschema": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -10395,7 +10070,6 @@ }, "node_modules/kind-of": { "version": "6.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10403,7 +10077,6 @@ }, "node_modules/klaw": { "version": "1.3.1", - "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.9" @@ -10495,7 +10168,6 @@ }, "node_modules/locate-path": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^2.0.0", @@ -10507,17 +10179,14 @@ }, "node_modules/lodash": { "version": "4.17.21", - "dev": true, "license": "MIT" }, "node_modules/lodash.camelcase": { "version": "4.3.0", - "dev": true, "license": "MIT" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", - "dev": true, "license": "MIT" }, "node_modules/lodash.defaults": { @@ -10539,12 +10208,10 @@ }, "node_modules/lodash.truncate": { "version": "4.4.2", - "dev": true, "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.0", @@ -10559,7 +10226,6 @@ }, "node_modules/log-symbols/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -10573,7 +10239,6 @@ }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -10588,7 +10253,6 @@ }, "node_modules/log-symbols/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -10599,12 +10263,10 @@ }, "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/log-symbols/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10612,7 +10274,6 @@ }, "node_modules/log-symbols/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10633,7 +10294,6 @@ }, "node_modules/loupe": { "version": "2.3.7", - "dev": true, "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" @@ -10652,7 +10312,6 @@ }, "node_modules/lru_map": { "version": "0.3.3", - "dev": true, "license": "MIT" }, "node_modules/lru-cache": { @@ -10674,12 +10333,10 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, "license": "ISC" }, "node_modules/markdown-table": { "version": "1.1.3", - "dev": true, "license": "MIT" }, "node_modules/match-all": { @@ -10688,7 +10345,6 @@ }, "node_modules/md5.js": { "version": "1.3.5", - "dev": true, "license": "MIT", "dependencies": { "hash-base": "^3.0.0", @@ -10698,7 +10354,6 @@ }, "node_modules/memorystream": { "version": "0.3.1", - "dev": true, "engines": { "node": ">= 0.10.0" } @@ -10709,7 +10364,6 @@ }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -10788,7 +10442,6 @@ }, "node_modules/minimatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10799,7 +10452,6 @@ }, "node_modules/minimist": { "version": "1.2.8", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10807,15 +10459,15 @@ }, "node_modules/minipass": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mkdirp": { "version": "0.5.6", - "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" @@ -10836,7 +10488,6 @@ }, "node_modules/mnemonist": { "version": "0.38.5", - "dev": true, "license": "MIT", "dependencies": { "obliterator": "^2.0.0" @@ -10844,7 +10495,6 @@ }, "node_modules/mocha": { "version": "10.2.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-colors": "4.1.1", @@ -10883,7 +10533,6 @@ }, "node_modules/mocha/node_modules/ansi-colors": { "version": "4.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -10891,7 +10540,6 @@ }, "node_modules/mocha/node_modules/brace-expansion": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -10899,7 +10547,6 @@ }, "node_modules/mocha/node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10910,7 +10557,6 @@ }, "node_modules/mocha/node_modules/find-up": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -10925,7 +10571,6 @@ }, "node_modules/mocha/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10933,7 +10578,6 @@ }, "node_modules/mocha/node_modules/locate-path": { "version": "6.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -10947,7 +10591,6 @@ }, "node_modules/mocha/node_modules/minimatch": { "version": "5.0.1", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -10958,12 +10601,10 @@ }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", - "dev": true, "license": "MIT" }, "node_modules/mocha/node_modules/p-limit": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -10977,7 +10618,6 @@ }, "node_modules/mocha/node_modules/p-locate": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -10991,7 +10631,6 @@ }, "node_modules/mocha/node_modules/path-exists": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10999,7 +10638,6 @@ }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -11049,7 +10687,6 @@ }, "node_modules/nanoid": { "version": "3.3.3", - "dev": true, "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" @@ -11065,7 +10702,6 @@ }, "node_modules/neo-async": { "version": "2.6.2", - "dev": true, "license": "MIT" }, "node_modules/next-tick": { @@ -11078,7 +10714,6 @@ }, "node_modules/node-emoji": { "version": "1.11.0", - "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.21" @@ -11138,7 +10773,6 @@ }, "node_modules/nofilter": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12.19" @@ -11146,7 +10780,6 @@ }, "node_modules/nopt": { "version": "3.0.6", - "dev": true, "license": "ISC", "dependencies": { "abbrev": "1" @@ -11198,7 +10831,6 @@ }, "node_modules/number-to-bn": { "version": "1.7.0", - "dev": true, "license": "MIT", "dependencies": { "bn.js": "4.11.6", @@ -11211,12 +10843,10 @@ }, "node_modules/number-to-bn/node_modules/bn.js": { "version": "4.11.6", - "dev": true, "license": "MIT" }, "node_modules/object-assign": { "version": "4.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11299,7 +10929,6 @@ }, "node_modules/obliterator": { "version": "2.0.4", - "dev": true, "license": "MIT" }, "node_modules/ofetch": { @@ -11357,12 +10986,10 @@ }, "node_modules/ordinal": { "version": "1.0.3", - "dev": true, "license": "MIT" }, "node_modules/os-tmpdir": { "version": "1.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11378,7 +11005,6 @@ }, "node_modules/p-limit": { "version": "1.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^1.0.0" @@ -11389,7 +11015,6 @@ }, "node_modules/p-locate": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^1.1.0" @@ -11400,7 +11025,6 @@ }, "node_modules/p-map": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" @@ -11414,7 +11038,6 @@ }, "node_modules/p-try": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11474,8 +11097,7 @@ } }, "node_modules/parse-cache-control": { - "version": "1.0.1", - "dev": true + "version": "1.0.1" }, "node_modules/parse-json": { "version": "5.2.0", @@ -11496,7 +11118,6 @@ }, "node_modules/path-exists": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11504,7 +11125,6 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11519,13 +11139,13 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11539,7 +11159,6 @@ }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11551,7 +11170,6 @@ }, "node_modules/pathval": { "version": "1.1.1", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -11559,7 +11177,6 @@ }, "node_modules/pbkdf2": { "version": "3.1.2", - "dev": true, "license": "MIT", "dependencies": { "create-hash": "^1.1.2", @@ -11588,7 +11205,6 @@ }, "node_modules/pify": { "version": "4.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11788,7 +11404,6 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, "license": "MIT" }, "node_modules/process-warning": { @@ -11797,7 +11412,6 @@ }, "node_modules/promise": { "version": "8.3.0", - "dev": true, "license": "MIT", "dependencies": { "asap": "~2.0.6" @@ -11818,7 +11432,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12047,7 +11660,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -12085,7 +11697,6 @@ }, "node_modules/randombytes": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -12093,7 +11704,6 @@ }, "node_modules/raw-body": { "version": "2.5.2", - "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -12179,7 +11789,6 @@ }, "node_modules/rechoir": { "version": "0.6.2", - "dev": true, "dependencies": { "resolve": "^1.1.6" }, @@ -12189,7 +11798,6 @@ }, "node_modules/recursive-readdir": { "version": "2.2.3", - "dev": true, "license": "MIT", "dependencies": { "minimatch": "^3.0.5" @@ -12217,7 +11825,6 @@ }, "node_modules/reduce-flatten": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12266,7 +11873,6 @@ }, "node_modules/req-cwd": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "req-from": "^2.0.0" @@ -12277,7 +11883,6 @@ }, "node_modules/req-from": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "resolve-from": "^3.0.0" @@ -12288,7 +11893,6 @@ }, "node_modules/req-from/node_modules/resolve-from": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -12303,7 +11907,6 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12315,7 +11918,6 @@ }, "node_modules/resolve": { "version": "1.17.0", - "dev": true, "license": "MIT", "dependencies": { "path-parse": "^1.0.6" @@ -12361,7 +11963,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -12369,19 +11970,71 @@ } }, "node_modules/rimraf": { - "version": "2.7.1", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", "dev": true, - "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^10.3.7" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ripemd160": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "hash-base": "^3.0.0", @@ -12390,7 +12043,6 @@ }, "node_modules/rlp": { "version": "2.2.7", - "dev": true, "license": "MPL-2.0", "dependencies": { "bn.js": "^5.2.0" @@ -12432,7 +12084,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -12495,12 +12146,10 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, "license": "MIT" }, "node_modules/sc-istanbul": { "version": "0.4.6", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "abbrev": "1.0.x", @@ -12524,7 +12173,6 @@ }, "node_modules/sc-istanbul/node_modules/argparse": { "version": "1.0.10", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -12532,7 +12180,6 @@ }, "node_modules/sc-istanbul/node_modules/glob": { "version": "5.0.15", - "dev": true, "license": "ISC", "dependencies": { "inflight": "^1.0.4", @@ -12547,7 +12194,6 @@ }, "node_modules/sc-istanbul/node_modules/has-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12555,7 +12201,6 @@ }, "node_modules/sc-istanbul/node_modules/js-yaml": { "version": "3.14.1", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -12567,7 +12212,6 @@ }, "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { "version": "4.0.1", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -12579,12 +12223,10 @@ }, "node_modules/sc-istanbul/node_modules/resolve": { "version": "1.1.7", - "dev": true, "license": "MIT" }, "node_modules/sc-istanbul/node_modules/supports-color": { "version": "3.2.3", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^1.0.0" @@ -12595,7 +12237,6 @@ }, "node_modules/sc-istanbul/node_modules/which": { "version": "1.3.1", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -12617,7 +12258,6 @@ }, "node_modules/secp256k1": { "version": "4.0.3", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -12631,7 +12271,6 @@ }, "node_modules/semver": { "version": "6.3.1", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -12639,7 +12278,6 @@ }, "node_modules/serialize-javascript": { "version": "6.0.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -12677,12 +12315,10 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "dev": true, "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "dev": true, "license": "ISC" }, "node_modules/sha.js": { @@ -12698,7 +12334,6 @@ }, "node_modules/sha1": { "version": "1.1.1", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "charenc": ">= 0.0.1", @@ -12727,7 +12362,6 @@ }, "node_modules/shelljs": { "version": "0.8.5", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "glob": "^7.0.0", @@ -12765,7 +12399,6 @@ }, "node_modules/slash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12773,7 +12406,6 @@ }, "node_modules/slice-ansi": { "version": "4.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -12789,7 +12421,6 @@ }, "node_modules/slice-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -12803,7 +12434,6 @@ }, "node_modules/slice-ansi/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -12814,12 +12444,10 @@ }, "node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/solc": { "version": "0.7.3", - "dev": true, "license": "MIT", "dependencies": { "command-exists": "^1.2.8", @@ -12841,7 +12469,6 @@ }, "node_modules/solc/node_modules/fs-extra": { "version": "0.30.0", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2", @@ -12853,15 +12480,24 @@ }, "node_modules/solc/node_modules/jsonfile": { "version": "2.4.0", - "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, + "node_modules/solc/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/solc/node_modules/semver": { "version": "5.7.2", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -13062,7 +12698,6 @@ }, "node_modules/solidity-coverage": { "version": "0.8.7", - "dev": true, "license": "ISC", "dependencies": { "@ethersproject/abi": "^5.0.9", @@ -13094,12 +12729,10 @@ }, "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { "version": "0.18.0", - "dev": true, "license": "MIT" }, "node_modules/solidity-coverage/node_modules/fs-extra": { "version": "8.1.0", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -13112,7 +12745,6 @@ }, "node_modules/solidity-coverage/node_modules/globby": { "version": "10.0.2", - "dev": true, "license": "MIT", "dependencies": { "@types/glob": "^7.1.1", @@ -13130,7 +12762,6 @@ }, "node_modules/solidity-coverage/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -13141,7 +12772,6 @@ }, "node_modules/solidity-coverage/node_modules/semver": { "version": "7.5.4", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -13162,7 +12792,6 @@ }, "node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -13177,7 +12806,6 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -13200,12 +12828,10 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/stacktrace-parser": { "version": "0.1.10", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.7.1" @@ -13216,7 +12842,6 @@ }, "node_modules/stacktrace-parser/node_modules/type-fest": { "version": "0.7.1", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" @@ -13228,7 +12853,6 @@ }, "node_modules/statuses": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -13276,7 +12900,6 @@ }, "node_modules/string-format": { "version": "2.0.0", - "dev": true, "license": "WTFPL OR MIT" }, "node_modules/string-width": { @@ -13294,8 +12917,9 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13360,8 +12984,9 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13389,7 +13014,6 @@ }, "node_modules/strip-hex-prefix": { "version": "1.0.0", - "dev": true, "license": "MIT", "dependencies": { "is-hex-prefixed": "1.0.0" @@ -13401,7 +13025,6 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13423,7 +13046,6 @@ }, "node_modules/supports-color": { "version": "5.5.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -13445,7 +13067,6 @@ }, "node_modules/sync-request": { "version": "6.1.0", - "dev": true, "license": "MIT", "dependencies": { "http-response-object": "^3.0.1", @@ -13458,7 +13079,6 @@ }, "node_modules/sync-rpc": { "version": "1.3.6", - "dev": true, "license": "MIT", "dependencies": { "get-port": "^3.1.0" @@ -13496,7 +13116,6 @@ }, "node_modules/table": { "version": "6.8.1", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", @@ -13511,7 +13130,6 @@ }, "node_modules/table-layout": { "version": "1.0.2", - "dev": true, "license": "MIT", "dependencies": { "array-back": "^4.0.1", @@ -13525,7 +13143,6 @@ }, "node_modules/table-layout/node_modules/array-back": { "version": "4.0.2", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13533,7 +13150,6 @@ }, "node_modules/table-layout/node_modules/typical": { "version": "5.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13541,7 +13157,6 @@ }, "node_modules/table/node_modules/ajv": { "version": "8.12.0", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -13556,7 +13171,6 @@ }, "node_modules/table/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/text-table": { @@ -13566,7 +13180,6 @@ }, "node_modules/then-request": { "version": "6.0.2", - "dev": true, "license": "MIT", "dependencies": { "@types/concat-stream": "^1.6.0", @@ -13587,12 +13200,10 @@ }, "node_modules/then-request/node_modules/@types/node": { "version": "8.10.66", - "dev": true, "license": "MIT" }, "node_modules/then-request/node_modules/form-data": { "version": "2.5.1", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -13612,7 +13223,6 @@ }, "node_modules/tmp": { "version": "0.0.33", - "dev": true, "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" @@ -13633,7 +13243,6 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.6" @@ -13656,7 +13265,6 @@ }, "node_modules/ts-command-line-args": { "version": "2.5.1", - "dev": true, "license": "ISC", "dependencies": { "chalk": "^4.1.0", @@ -13670,7 +13278,6 @@ }, "node_modules/ts-command-line-args/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -13684,7 +13291,6 @@ }, "node_modules/ts-command-line-args/node_modules/chalk": { "version": "4.1.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -13699,7 +13305,6 @@ }, "node_modules/ts-command-line-args/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -13710,12 +13315,10 @@ }, "node_modules/ts-command-line-args/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/ts-command-line-args/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13723,7 +13326,6 @@ }, "node_modules/ts-command-line-args/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -13734,7 +13336,6 @@ }, "node_modules/ts-essentials": { "version": "7.0.3", - "dev": true, "license": "MIT", "peerDependencies": { "typescript": ">=3.7.0" @@ -13742,7 +13343,6 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -13784,7 +13384,6 @@ }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -13807,7 +13406,6 @@ }, "node_modules/tsort": { "version": "0.0.1", - "dev": true, "license": "MIT" }, "node_modules/tsx": { @@ -13830,12 +13428,10 @@ }, "node_modules/tweetnacl": { "version": "1.0.3", - "dev": true, "license": "Unlicense" }, "node_modules/tweetnacl-util": { "version": "0.15.1", - "dev": true, "license": "Unlicense" }, "node_modules/type": { @@ -13855,7 +13451,6 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -13863,7 +13458,6 @@ }, "node_modules/type-fest": { "version": "0.21.3", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -13874,7 +13468,6 @@ }, "node_modules/typechain": { "version": "8.3.2", - "dev": true, "license": "MIT", "dependencies": { "@types/prettier": "^2.1.1", @@ -13897,7 +13490,6 @@ }, "node_modules/typechain/node_modules/glob": { "version": "7.1.7", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -13916,7 +13508,6 @@ }, "node_modules/typechain/node_modules/mkdirp": { "version": "1.0.4", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -13927,7 +13518,6 @@ }, "node_modules/typechain/node_modules/prettier": { "version": "2.8.8", - "dev": true, "license": "MIT", "bin": { "prettier": "bin-prettier.js" @@ -14002,7 +13592,6 @@ }, "node_modules/typedarray": { "version": "0.0.6", - "dev": true, "license": "MIT" }, "node_modules/typedarray-to-buffer": { @@ -14025,7 +13614,6 @@ }, "node_modules/typical": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14037,7 +13625,6 @@ }, "node_modules/uglify-js": { "version": "3.17.4", - "dev": true, "license": "BSD-2-Clause", "optional": true, "peer": true, @@ -14075,7 +13662,6 @@ }, "node_modules/undici": { "version": "5.28.3", - "dev": true, "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" @@ -14086,7 +13672,6 @@ }, "node_modules/undici-types": { "version": "5.26.5", - "dev": true, "license": "MIT" }, "node_modules/unenv": { @@ -14106,7 +13691,6 @@ }, "node_modules/universalify": { "version": "0.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">= 4.0.0" @@ -14114,7 +13698,6 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -14207,7 +13790,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -14233,7 +13815,6 @@ }, "node_modules/utf8": { "version": "3.0.0", - "dev": true, "license": "MIT" }, "node_modules/util-deprecate": { @@ -14242,7 +13823,6 @@ }, "node_modules/uuid": { "version": "8.3.2", - "dev": true, "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -14250,7 +13830,6 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, "license": "MIT" }, "node_modules/valtio": { @@ -14463,7 +14042,6 @@ }, "node_modules/web3-utils": { "version": "1.10.3", - "dev": true, "license": "LGPL-3.0", "dependencies": { "@ethereumjs/util": "^8.1.0", @@ -14481,7 +14059,6 @@ }, "node_modules/web3-utils/node_modules/@noble/curves": { "version": "1.1.0", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "1.3.1" @@ -14492,7 +14069,6 @@ }, "node_modules/web3-utils/node_modules/@noble/hashes": { "version": "1.3.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 16" @@ -14503,7 +14079,6 @@ }, "node_modules/web3-utils/node_modules/@scure/bip32": { "version": "1.3.1", - "dev": true, "license": "MIT", "dependencies": { "@noble/curves": "~1.1.0", @@ -14516,7 +14091,6 @@ }, "node_modules/web3-utils/node_modules/@scure/bip39": { "version": "1.2.1", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "~1.3.0", @@ -14528,7 +14102,6 @@ }, "node_modules/web3-utils/node_modules/ethereum-cryptography": { "version": "2.1.2", - "dev": true, "license": "MIT", "dependencies": { "@noble/curves": "1.1.0", @@ -14627,7 +14200,6 @@ }, "node_modules/widest-line": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "string-width": "^4.0.0" @@ -14638,7 +14210,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14646,12 +14217,10 @@ }, "node_modules/wordwrap": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/wordwrapjs": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "reduce-flatten": "^2.0.0", @@ -14663,7 +14232,6 @@ }, "node_modules/wordwrapjs/node_modules/typical": { "version": "5.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -14671,12 +14239,10 @@ }, "node_modules/workerpool": { "version": "6.2.1", - "dev": true, "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -14693,8 +14259,9 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -14709,8 +14276,9 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -14723,8 +14291,9 @@ }, "node_modules/wrap-ansi-cjs/node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -14734,12 +14303,12 @@ }, "node_modules/wrap-ansi-cjs/node_modules/color-name": { "version": "1.1.4", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -14753,7 +14322,6 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -14764,7 +14332,6 @@ }, "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/wrappy": { @@ -14799,7 +14366,6 @@ }, "node_modules/y18n": { "version": "5.0.8", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -14818,7 +14384,6 @@ }, "node_modules/yargs": { "version": "16.2.0", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^7.0.2", @@ -14835,7 +14400,6 @@ }, "node_modules/yargs-parser": { "version": "20.2.4", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -14843,7 +14407,6 @@ }, "node_modules/yargs-unparser": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "camelcase": "^6.0.0", @@ -14857,7 +14420,6 @@ }, "node_modules/yn": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -14865,7 +14427,6 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -15138,13 +14699,314 @@ "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" + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@safe-global/safe-4337-provider": "^0.0.0", + "ethers": "^6.11.1", + "hardhat-deploy": "^0.12.1", + "node-fetch": "^2.7.0" }, "bin": { - "local-bundler-test": "dist/bin/test.js" + "4337-local-bundler-test": "dist/bin/test.js" + } + }, + "packages/4337-local-bundler/node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" + }, + "packages/4337-local-bundler/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/4337-local-bundler/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/4337-local-bundler/node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.6.tgz", + "integrity": "sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ==", + "peer": true, + "dependencies": { + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "chai": "^4.2.0", + "ethers": "^6.1.0", + "hardhat": "^2.9.4" + } + }, + "packages/4337-local-bundler/node_modules/@nomicfoundation/hardhat-ethers": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", + "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", + "peer": true, + "dependencies": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "ethers": "^6.1.0", + "hardhat": "^2.0.0" + } + }, + "packages/4337-local-bundler/node_modules/@nomicfoundation/hardhat-toolbox": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz", + "integrity": "sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA==", + "peerDependencies": { + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "@typechain/ethers-v6": "^0.5.0", + "@typechain/hardhat": "^9.0.0", + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "@types/node": ">=16.0.0", + "chai": "^4.2.0", + "ethers": "^6.4.0", + "hardhat": "^2.11.0", + "hardhat-gas-reporter": "^1.0.8", + "solidity-coverage": "^0.8.1", + "ts-node": ">=8.0.0", + "typechain": "^8.3.0", + "typescript": ">=4.5.0" + } + }, + "packages/4337-local-bundler/node_modules/@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "ethers": "6.x", + "typechain": "^8.3.2", + "typescript": ">=4.7.0" + } + }, + "packages/4337-local-bundler/node_modules/@typechain/hardhat": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz", + "integrity": "sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA==", + "peer": true, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "peerDependencies": { + "@typechain/ethers-v6": "^0.5.1", + "ethers": "^6.1.0", + "hardhat": "^2.9.9", + "typechain": "^8.3.2" + } + }, + "packages/4337-local-bundler/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "packages/4337-local-bundler/node_modules/ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/4337-local-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "packages/4337-local-bundler/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "packages/4337-local-bundler/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "packages/4337-local-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "packages/4337-local-bundler/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "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 + } + } + }, + "packages/4337-provider": { + "name": "@safe-global/safe-4337-provider", + "version": "0.0.0", + "license": "LGPL-3.0-only", + "dependencies": { + "ethers": "^6.11.1" + } + }, + "packages/4337-provider/node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" + }, + "packages/4337-provider/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/4337-provider/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/4337-provider/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "packages/4337-provider/node_modules/ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "packages/4337-provider/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "packages/4337-provider/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "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 + } } } } diff --git a/package.json b/package.json index aa48f743..edccf0ff 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "A monorepo for Safe modules", "main": "dist/index.js", "workspaces": [ - "modules/*", "packages/*", + "modules/*", "examples/*" ], "scripts": { @@ -39,6 +39,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", "prettier": "^3.2.5", - "prettier-plugin-solidity": "^1.3.1" + "prettier-plugin-solidity": "^1.3.1", + "rimraf": "^5.0.5" } } diff --git a/packages/4337-local-bundler/package.json b/packages/4337-local-bundler/package.json index ceaf6e91..d9d5f3e7 100644 --- a/packages/4337-local-bundler/package.json +++ b/packages/4337-local-bundler/package.json @@ -9,14 +9,15 @@ "4337-local-bundler-test": "dist/bin/test.js" }, "scripts": { - "build": "npx rimraf dist && tsc && chmod +x dist/bin/*.js", + "build": "rimraf dist && tsc && chmod +x dist/bin/*.js", "lint": "eslint .", - "prepack": "npm run build", - "prepublish": "npm run build", - "postinstall": "npm run build" + "prepare": "npm run build -w ../4337-provider && npm run build" }, "dependencies": { + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@safe-global/safe-4337-provider": "^0.0.0", "hardhat-deploy": "^0.12.1", + "ethers": "^6.11.1", "node-fetch": "^2.7.0" } } diff --git a/packages/4337-local-bundler/src/index.ts b/packages/4337-local-bundler/src/index.ts index 3d2da4d3..ef730dc9 100644 --- a/packages/4337-local-bundler/src/index.ts +++ b/packages/4337-local-bundler/src/index.ts @@ -1,6 +1,6 @@ -import 'hardhat-deploy' - import deployEntryPoint from './deploy/entrypoint' import deploySafe from './deploy/safe' +export * from './testing' + export { deployEntryPoint, deploySafe } diff --git a/modules/4337/test/utils/e2e.ts b/packages/4337-local-bundler/src/testing.ts similarity index 68% rename from modules/4337/test/utils/e2e.ts rename to packages/4337-local-bundler/src/testing.ts index 445deae4..396ca459 100644 --- a/modules/4337/test/utils/e2e.ts +++ b/packages/4337-local-bundler/src/testing.ts @@ -1,12 +1,22 @@ +import { MultiProvider4337, UserOperation } from '@safe-global/safe-4337-provider' +import { HDNodeWallet } from 'ethers' import { deployments, ethers } from 'hardhat' -import { MultiProvider4337 } from '../../src/utils/safe' -import { UserOperation } from '../../src/utils/userOp' -import { AddressLike, BigNumberish, BytesLike, HDNodeWallet } from 'ethers' export const BUNDLER_URL = process.env.TEST_BUNLDER_URL || 'http://localhost:3000/rpc' export const BUNDLER_MNEMONIC = process.env.TEST_BUNDLER_MNEMONIC || 'test test test test test test test test test test test junk' -export async function prepareAccounts(mnemonic = BUNDLER_MNEMONIC, count = 1): Promise { +export type PrepareAccountOptions = { + mnemonic: string + count: number +} + +export async function prepareAccounts(options: Partial = {}): Promise { + const { mnemonic, count } = { + mnemonic: BUNDLER_MNEMONIC, + count: 1, + ...options, + } + const bundler = ethers.HDNodeWallet.fromPhrase(mnemonic).connect(ethers.provider) const accounts = [...Array(count)].map(() => ethers.Wallet.createRandom(ethers.provider)) @@ -39,18 +49,3 @@ export async function waitForUserOp({ sender, nonce }: Pick setTimeout(resolve, 10)) } } - -export interface MultiSendTransaction { - op: 0 | 1 - to: AddressLike - value?: BigNumberish - data: BytesLike -} - -export function encodeMultiSendTransactions(transactions: MultiSendTransaction[]) { - return ethers.concat( - transactions.map(({ op, to, value, data }) => - ethers.solidityPacked(['uint8', 'address', 'uint256', 'uint256', 'bytes'], [op, to, value ?? 0, ethers.dataLength(data), data]), - ), - ) -} diff --git a/packages/4337-local-bundler/src/types/hardhat.ts b/packages/4337-local-bundler/src/types/hardhat.ts new file mode 100644 index 00000000..23e5ec22 --- /dev/null +++ b/packages/4337-local-bundler/src/types/hardhat.ts @@ -0,0 +1,2 @@ +import '@nomicfoundation/hardhat-ethers' +import 'hardhat-deploy' diff --git a/packages/4337-provider/.eslintignore b/packages/4337-provider/.eslintignore new file mode 100644 index 00000000..849ddff3 --- /dev/null +++ b/packages/4337-provider/.eslintignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/4337-provider/.gitignore b/packages/4337-provider/.gitignore new file mode 100644 index 00000000..849ddff3 --- /dev/null +++ b/packages/4337-provider/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/packages/4337-provider/README.md b/packages/4337-provider/README.md new file mode 100644 index 00000000..d61f341c --- /dev/null +++ b/packages/4337-provider/README.md @@ -0,0 +1,3 @@ +# ERC-4337 Ethers Provider + +This package contains an Ethers.js RPC provider with support for interacting with ERC-4337 bundlers. diff --git a/packages/4337-provider/package.json b/packages/4337-provider/package.json new file mode 100644 index 00000000..01cd048d --- /dev/null +++ b/packages/4337-provider/package.json @@ -0,0 +1,16 @@ +{ + "name": "@safe-global/safe-4337-provider", + "version": "0.0.0", + "private": true, + "license": "LGPL-3.0-only", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "rimraf dist && tsc", + "lint": "eslint .", + "prepare": "npm run build" + }, + "dependencies": { + "ethers": "^6.11.1" + } +} diff --git a/packages/4337-provider/src/index.ts b/packages/4337-provider/src/index.ts new file mode 100644 index 00000000..c17cea97 --- /dev/null +++ b/packages/4337-provider/src/index.ts @@ -0,0 +1,74 @@ +import { ethers, AddressLike, BigNumberish, BytesLike, Provider, JsonRpcProvider } from 'ethers' + +export interface RpcProvider extends Provider { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + send(method: string, params: unknown[]): Promise +} + +export type UserOperation = { + sender: string + nonce: BigNumberish + factory?: string + factoryData?: BytesLike + callData: BytesLike + callGasLimit: BigNumberish + verificationGasLimit: BigNumberish + preVerificationGas: BigNumberish + maxFeePerGas: BigNumberish + maxPriorityFeePerGas: BigNumberish + paymaster?: string + paymasterVerificationGasLimit?: BigNumberish + paymasterPostOpGasLimit?: BigNumberish + paymasterData?: BytesLike + signature: BytesLike +} + +export class MultiProvider4337 extends JsonRpcProvider { + generalProvider: RpcProvider + constructor(aaProviderUrl: string, generalProvider: RpcProvider) { + super(aaProviderUrl) + this.generalProvider = generalProvider + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + send(method: string, params: unknown[]): Promise { + if ( + [ + 'eth_supportedEntryPoints', + 'eth_estimateUserOperationGas', + 'eth_sendUserOperation', + 'eth_getUserOperationByHash', + 'eth_getUserOperationReceipt', + ].indexOf(method) >= 0 + ) { + return super.send(method, params) + } else { + return this.generalProvider.send(method, params) + } + } + + public async sendUserOperation(userOp: UserOperation, entryPoint: AddressLike): Promise { + const jsonUserOp = { + sender: ethers.getAddress(userOp.sender), + nonce: ethers.toBeHex(userOp.nonce), + callData: ethers.hexlify(userOp.callData), + callGasLimit: ethers.toBeHex(userOp.callGasLimit), + verificationGasLimit: ethers.toBeHex(userOp.verificationGasLimit), + preVerificationGas: ethers.toBeHex(userOp.preVerificationGas), + maxFeePerGas: ethers.toBeHex(userOp.maxFeePerGas), + maxPriorityFeePerGas: ethers.toBeHex(userOp.maxPriorityFeePerGas), + signature: ethers.hexlify(userOp.signature), + } as Record + if (userOp.factory) { + jsonUserOp.factory = ethers.getAddress(userOp.factory) + jsonUserOp.factoryData = ethers.hexlify(userOp.factoryData!) + } + if (userOp.paymaster) { + jsonUserOp.paymaster = ethers.getAddress(userOp.paymaster) + jsonUserOp.paymasterVerificationGasLimit = ethers.toBeHex(userOp.paymasterVerificationGasLimit!) + jsonUserOp.paymasterPostOpGasLimit = ethers.toBeHex(userOp.paymasterPostOpGasLimit!) + jsonUserOp.paymasterData = ethers.hexlify(userOp.paymasterData!) + } + return await super.send('eth_sendUserOperation', [jsonUserOp, await ethers.resolveAddress(entryPoint, this)]) + } +} diff --git a/packages/4337-provider/tsconfig.json b/packages/4337-provider/tsconfig.json new file mode 100644 index 00000000..0ae3997d --- /dev/null +++ b/packages/4337-provider/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 + } +} From 4ad1f0c2f646cba3c44d2803123d85642164b25b Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Mon, 18 Mar 2024 15:34:43 +0100 Subject: [PATCH 3/3] Refactor Contract Layout (#319) This PR changes the contract layout in the `passkey` package, as well as some small renames. It also changes constants to be used as `library`-ies instead of `contract`s that are inherited (to be more consistent, as both were used previously). There are almost no logic changes, some notable examples that came with the refactor: 1. Since `SignatureData` needed to be shared by the `WebAuthnSigner` and `WebAuthnSignerFactory`, I created a `WebAuthnSignature` library that declares the stuck and includes the casting logic. This lead to some small changes in the `WebAuthnSignerFactory` notably to work around some "stack too deep" error that didn't happen before. 2. The `WebAuthnConstants` is now `WebAuthnFlags` and I **removed** the `AUTH_DATA_FLAGS_BE` and `AUTH_DATA_FLAGS_BS` because they aren't actual flags :shrug:. Don't know how they got there, but the bits in those flags are officially [reserved for future use](https://www.w3.org/TR/webauthn-2/#sctn-authenticator-data). I also didn't bother adding the `AT` and `ET` flags, since those can't really be verified on-chain anyway and not really relevant from a signature verification perspective (they indicate what additional data is available in the authenticator data blob, but we don't make use of it anyway). --- .../4337/Safe256BitECSignerLaunchpad.sol | 11 +- .../contracts/SignatureValidatorConstants.sol | 15 --- modules/passkey/contracts/WebAuthnSigner.sol | 126 ++---------------- .../contracts/WebAuthnSignerFactory.sol | 86 ++++++++++++ .../{ => base}/SignatureValidator.sol | 13 +- .../interfaces/ICustomSignerFactory.sol | 4 +- .../contracts/interfaces/IP256Verifier.sol | 34 +++++ .../passkey/contracts/interfaces/ISafe.sol | 2 +- .../interfaces/IWebAuthnVerifier.sol | 56 ++++++++ .../passkey/contracts/libraries/ERC1271.sol | 24 ++++ .../IP256Verifier.sol => libraries/P256.sol} | 41 +----- .../contracts/libraries/WebAuthnFlags.sol | 42 ++++++ .../contracts/libraries/WebAuthnSignature.sol | 44 ++++++ .../passkey/contracts/test/BadP256Verfier.sol | 2 +- ...estP256VerifierLib.sol => TestP256Lib.sol} | 7 +- .../test/TestWebAuthnSignerFactory.sol | 5 +- .../contracts/verifiers/FCLP256Verifier.sol | 6 +- .../contracts/verifiers/WebAuthnVerifier.sol | 109 +++------------ .../P256.spec.ts} | 28 ++-- 19 files changed, 362 insertions(+), 293 deletions(-) delete mode 100644 modules/passkey/contracts/SignatureValidatorConstants.sol create mode 100644 modules/passkey/contracts/WebAuthnSignerFactory.sol rename modules/passkey/contracts/{ => base}/SignatureValidator.sol (80%) create mode 100644 modules/passkey/contracts/interfaces/IP256Verifier.sol create mode 100644 modules/passkey/contracts/interfaces/IWebAuthnVerifier.sol create mode 100644 modules/passkey/contracts/libraries/ERC1271.sol rename modules/passkey/contracts/{verifiers/IP256Verifier.sol => libraries/P256.sol} (68%) create mode 100644 modules/passkey/contracts/libraries/WebAuthnFlags.sol create mode 100644 modules/passkey/contracts/libraries/WebAuthnSignature.sol rename modules/passkey/contracts/test/{TestP256VerifierLib.sol => TestP256Lib.sol} (80%) rename modules/passkey/test/{verifiers/P256VerfierLib.spec.ts => libraries/P256.spec.ts} (57%) diff --git a/modules/passkey/contracts/4337/Safe256BitECSignerLaunchpad.sol b/modules/passkey/contracts/4337/Safe256BitECSignerLaunchpad.sol index c9de10c9..5e286e49 100644 --- a/modules/passkey/contracts/4337/Safe256BitECSignerLaunchpad.sol +++ b/modules/passkey/contracts/4337/Safe256BitECSignerLaunchpad.sol @@ -5,15 +5,16 @@ import {IAccount} from "@account-abstraction/contracts/interfaces/IAccount.sol"; import {PackedUserOperation} from "@account-abstraction/contracts/interfaces/PackedUserOperation.sol"; import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.sol"; import {SafeStorage} from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; -import {SignatureValidatorConstants} from "../SignatureValidatorConstants.sol"; + import {ICustom256BitECSignerFactory} from "../interfaces/ICustomSignerFactory.sol"; -import {ISafeSetup} from "../interfaces/ISafe.sol"; +import {ISafe} from "../interfaces/ISafe.sol"; +import {ERC1271} from "../libraries/ERC1271.sol"; /** * @title SafeOpLaunchpad - A contract for Safe initialization with custom unique signers that would violate ERC-4337 factory rules. * @dev The is intended to be set as a Safe proxy's implementation for ERC-4337 user operation that deploys the account. */ -contract Safe256BitECSignerLaunchpad is IAccount, SafeStorage, SignatureValidatorConstants { +contract Safe256BitECSignerLaunchpad is IAccount, SafeStorage { bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); // keccak256("SafeSignerLaunchpad.initHash") - 1 @@ -197,7 +198,7 @@ contract Safe256BitECSignerLaunchpad is IAccount, SafeStorage, SignatureValidato ) returns (bytes4 magicValue) { // The timestamps are validated by the entry point, therefore we will not check them again - validationData = _packValidationData(magicValue != EIP1271_MAGIC_VALUE, validUntil, validAfter); + validationData = _packValidationData(magicValue != ERC1271.MAGIC_VALUE, validUntil, validAfter); } catch { validationData = _packValidationData(true, validUntil, validAfter); } @@ -219,7 +220,7 @@ contract Safe256BitECSignerLaunchpad is IAccount, SafeStorage, SignatureValidato address[] memory owners = new address[](1); owners[0] = ICustom256BitECSignerFactory(signerFactory).createSigner(signerX, signerY, signerVerifier); - ISafeSetup(address(this)).setup(owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0))); + ISafe(address(this)).setup(owners, 1, setupTo, setupData, fallbackHandler, address(0), 0, payable(address(0))); } (bool success, bytes memory returnData) = address(this).delegatecall(callData); diff --git a/modules/passkey/contracts/SignatureValidatorConstants.sol b/modules/passkey/contracts/SignatureValidatorConstants.sol deleted file mode 100644 index 06d5f1d2..00000000 --- a/modules/passkey/contracts/SignatureValidatorConstants.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -/* solhint-disable one-contract-per-file */ -pragma solidity >=0.7.0 <0.9.0; - -/** - * @title SignatureValidatorConstants - * @dev This contract defines the constants used for EIP-1271 signature validation. - */ -contract SignatureValidatorConstants { - // bytes4(keccak256("isValidSignature(bytes32,bytes)") - bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; - - // bytes4(keccak256("isValidSignature(bytes,bytes)") - bytes4 internal constant LEGACY_EIP1271_MAGIC_VALUE = 0x20c13b0b; -} diff --git a/modules/passkey/contracts/WebAuthnSigner.sol b/modules/passkey/contracts/WebAuthnSigner.sol index fba58f56..1ccfd5a6 100644 --- a/modules/passkey/contracts/WebAuthnSigner.sol +++ b/modules/passkey/contracts/WebAuthnSigner.sol @@ -1,21 +1,15 @@ // SPDX-License-Identifier: LGPL-3.0-only -/* solhint-disable one-contract-per-file */ pragma solidity >=0.8.0; -import {SignatureValidatorConstants} from "./SignatureValidatorConstants.sol"; -import {ICustom256BitECSignerFactory} from "./interfaces/ICustomSignerFactory.sol"; -import {SignatureValidator} from "./SignatureValidator.sol"; -import {IWebAuthnVerifier, WebAuthnConstants} from "./verifiers/WebAuthnVerifier.sol"; - -struct SignatureData { - bytes authenticatorData; - bytes clientDataFields; - uint256[2] rs; -} +import {SignatureValidator} from "./base/SignatureValidator.sol"; +import {IWebAuthnVerifier} from "./interfaces/IWebAuthnVerifier.sol"; +import {WebAuthnFlags} from "./libraries/WebAuthnFlags.sol"; +import {WebAuthnSignature} from "./libraries/WebAuthnSignature.sol"; /** - * @title WebAuthnSigner + * @title WebAuthn Safe Signature Validator * @dev A contract that represents a WebAuthn signer. + * @custom:security-contact bounty@safe.global */ contract WebAuthnSigner is SignatureValidator { uint256 public immutable X; @@ -38,114 +32,18 @@ contract WebAuthnSigner is SignatureValidator { * @inheritdoc SignatureValidator */ function _verifySignature(bytes32 message, bytes calldata signature) internal view virtual override returns (bool isValid) { - SignatureData calldata signaturePointer; - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - signaturePointer := signature.offset - } + WebAuthnSignature.Data calldata data = WebAuthnSignature.cast(signature); return WEBAUTHN_SIG_VERIFIER.verifyWebAuthnSignatureAllowMalleability( - signaturePointer.authenticatorData, - WebAuthnConstants.AUTH_DATA_FLAGS_UV, + data.authenticatorData, + WebAuthnFlags.USER_VERIFICATION, message, - signaturePointer.clientDataFields, - signaturePointer.rs, + data.clientDataFields, + data.r, + data.s, X, Y ); } } - -/** - * @title WebAuthnSignerFactory - * @dev A factory contract for creating and managing WebAuthn signers. - */ -contract WebAuthnSignerFactory is ICustom256BitECSignerFactory, SignatureValidatorConstants { - // @inheritdoc ICustom256BitECSignerFactory - function getSigner(uint256 qx, uint256 qy, address verifier) public view override returns (address signer) { - bytes32 codeHash = keccak256(abi.encodePacked(type(WebAuthnSigner).creationCode, qx, qy, uint256(uint160(verifier)))); - signer = address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash))))); - } - - // @inheritdoc ICustom256BitECSignerFactory - function createSigner(uint256 qx, uint256 qy, address verifier) external returns (address signer) { - signer = getSigner(qx, qy, verifier); - - if (_hasNoCode(signer) && _validVerifier(verifier)) { - WebAuthnSigner created = new WebAuthnSigner{salt: bytes32(0)}(qx, qy, verifier); - require(address(created) == signer); - } - } - - /** - * @dev Checks if the given verifier address contains code. - * @param verifier The address of the verifier to check. - * @return A boolean indicating whether the verifier contains code or not. - */ - function _validVerifier(address verifier) internal view returns (bool) { - // The verifier should contain code (The only way to implement a webauthn verifier is with a smart contract) - return !_hasNoCode(verifier); - } - - // @inheritdoc ICustom256BitECSignerFactory - function isValidSignatureForSigner( - uint256 qx, - uint256 qy, - address verifier, - bytes32 message, - bytes calldata signature - ) external view override returns (bytes4 magicValue) { - if (checkSignature(verifier, message, signature, qx, qy)) { - magicValue = EIP1271_MAGIC_VALUE; - } - } - - /** - * @dev Checks if the provided account has no code. - * @param account The address of the account to check. - * @return True if the account has no code, false otherwise. - */ - function _hasNoCode(address account) internal view returns (bool) { - uint256 size; - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - size := extcodesize(account) - } - return size == 0; - } - - /** - * @dev Checks the validity of a signature using WebAuthnVerifier. - * @param verifier The address of the WebAuthnVerifier contract. - * @param dataHash The hash of the data being signed. - * @param signature The signature to be verified. - * @param qx The x-coordinate of the public key. - * @param qy The y-coordinate of the public key. - * @return A boolean indicating whether the signature is valid or not. - */ - function checkSignature( - address verifier, - bytes32 dataHash, - bytes calldata signature, - uint256 qx, - uint256 qy - ) internal view returns (bool) { - SignatureData calldata signaturePointer; - // solhint-disable-next-line no-inline-assembly - assembly ("memory-safe") { - signaturePointer := signature.offset - } - - return - IWebAuthnVerifier(verifier).verifyWebAuthnSignatureAllowMalleability( - signaturePointer.authenticatorData, - WebAuthnConstants.AUTH_DATA_FLAGS_UV, - dataHash, - signaturePointer.clientDataFields, - signaturePointer.rs, - qx, - qy - ); - } -} diff --git a/modules/passkey/contracts/WebAuthnSignerFactory.sol b/modules/passkey/contracts/WebAuthnSignerFactory.sol new file mode 100644 index 00000000..a8ac73a7 --- /dev/null +++ b/modules/passkey/contracts/WebAuthnSignerFactory.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0; + +import {ICustom256BitECSignerFactory} from "./interfaces/ICustomSignerFactory.sol"; +import {IWebAuthnVerifier} from "./interfaces/IWebAuthnVerifier.sol"; +import {ERC1271} from "./libraries/ERC1271.sol"; +import {WebAuthnFlags} from "./libraries/WebAuthnFlags.sol"; +import {WebAuthnSignature} from "./libraries/WebAuthnSignature.sol"; +import {WebAuthnSigner} from "./WebAuthnSigner.sol"; + +/** + * @title WebAuthnSignerFactory + * @dev A factory contract for creating and managing WebAuthn signers. + */ +contract WebAuthnSignerFactory is ICustom256BitECSignerFactory { + // @inheritdoc ICustom256BitECSignerFactory + function getSigner(uint256 qx, uint256 qy, address verifier) public view override returns (address signer) { + bytes32 codeHash = keccak256(abi.encodePacked(type(WebAuthnSigner).creationCode, qx, qy, uint256(uint160(verifier)))); + signer = address(uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), bytes32(0), codeHash))))); + } + + // @inheritdoc ICustom256BitECSignerFactory + function createSigner(uint256 qx, uint256 qy, address verifier) external returns (address signer) { + signer = getSigner(qx, qy, verifier); + + if (_hasNoCode(signer) && _validVerifier(verifier)) { + WebAuthnSigner created = new WebAuthnSigner{salt: bytes32(0)}(qx, qy, verifier); + require(address(created) == signer); + } + } + + // @inheritdoc ICustom256BitECSignerFactory + function isValidSignatureForSigner( + uint256 qx, + uint256 qy, + address verifier, + bytes32 message, + bytes calldata signature + ) external view override returns (bytes4 magicValue) { + WebAuthnSignature.Data calldata data = WebAuthnSignature.cast(signature); + + // Work around stack-too-deep issues by helping out the compiler figure out how to re-order + // the stack. + uint256 x = qx; + uint256 y = qy; + + if ( + IWebAuthnVerifier(verifier).verifyWebAuthnSignatureAllowMalleability( + data.authenticatorData, + WebAuthnFlags.USER_VERIFICATION, + message, + data.clientDataFields, + data.r, + data.s, + x, + y + ) + ) { + magicValue = ERC1271.MAGIC_VALUE; + } + } + + /** + * @dev Checks if the given verifier address contains code. + * @param verifier The address of the verifier to check. + * @return A boolean indicating whether the verifier contains code or not. + */ + function _validVerifier(address verifier) internal view returns (bool) { + // The verifier should contain code (The only way to implement a webauthn verifier is with a smart contract) + return !_hasNoCode(verifier); + } + + /** + * @dev Checks if the provided account has no code. + * @param account The address of the account to check. + * @return True if the account has no code, false otherwise. + */ + function _hasNoCode(address account) internal view returns (bool) { + uint256 size; + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + size := extcodesize(account) + } + return size == 0; + } +} diff --git a/modules/passkey/contracts/SignatureValidator.sol b/modules/passkey/contracts/base/SignatureValidator.sol similarity index 80% rename from modules/passkey/contracts/SignatureValidator.sol rename to modules/passkey/contracts/base/SignatureValidator.sol index d6cf792e..d2816abc 100644 --- a/modules/passkey/contracts/SignatureValidator.sol +++ b/modules/passkey/contracts/base/SignatureValidator.sol @@ -1,13 +1,14 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.8.0; -import {SignatureValidatorConstants} from "./SignatureValidatorConstants.sol"; +import {ERC1271} from "../libraries/ERC1271.sol"; /** - * @title ISafeSigner - * @dev A interface for smart contract Safe owners that supports multiple `isValidSignature` versions. + * @title Signature Validator Base Contract + * @dev A interface for smart contract Safe owners that supports multiple ERC-1271 `isValidSignature` versions. + * @custom:security-contact bounty@safe.global */ -abstract contract SignatureValidator is SignatureValidatorConstants { +abstract contract SignatureValidator { /** * @dev Validates the signature for the given data. * @param data The signed data bytes. @@ -16,7 +17,7 @@ abstract contract SignatureValidator is SignatureValidatorConstants { */ function isValidSignature(bytes memory data, bytes calldata signature) external view returns (bytes4 magicValue) { if (_verifySignature(keccak256(data), signature)) { - magicValue = LEGACY_EIP1271_MAGIC_VALUE; + magicValue = ERC1271.LEGACY_MAGIC_VALUE; } } @@ -28,7 +29,7 @@ abstract contract SignatureValidator is SignatureValidatorConstants { */ function isValidSignature(bytes32 message, bytes calldata signature) external view returns (bytes4 magicValue) { if (_verifySignature(message, signature)) { - magicValue = EIP1271_MAGIC_VALUE; + magicValue = ERC1271.MAGIC_VALUE; } } diff --git a/modules/passkey/contracts/interfaces/ICustomSignerFactory.sol b/modules/passkey/contracts/interfaces/ICustomSignerFactory.sol index 0cbab63e..b68f8c92 100644 --- a/modules/passkey/contracts/interfaces/ICustomSignerFactory.sol +++ b/modules/passkey/contracts/interfaces/ICustomSignerFactory.sol @@ -4,7 +4,8 @@ pragma solidity >=0.8.0 <0.9.0; /** * @title ICustomECSignerFactory * @dev Interface for creating and verifying ECDSA signers. This is a generalized interface that should be - * compatible with curves of any order size. Currently not used in the project and exists here for reference. + * compatible with curves of any order size. Currently not used in the project and exists here for reference. + * @custom:security-contact bounty@safe.global */ interface ICustomECSignerFactory { /** @@ -42,6 +43,7 @@ interface ICustomECSignerFactory { /** * @title ICustom256BitECSignerFactory * @dev Interface for creating and verifying ECDSA signers using 256-bit elliptic curves. + * @custom:security-contact bounty@safe.global */ interface ICustom256BitECSignerFactory { /** diff --git a/modules/passkey/contracts/interfaces/IP256Verifier.sol b/modules/passkey/contracts/interfaces/IP256Verifier.sol new file mode 100644 index 00000000..f233e40c --- /dev/null +++ b/modules/passkey/contracts/interfaces/IP256Verifier.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable payable-fallback */ +pragma solidity ^0.8.0; + +/** + * @title P-256 Elliptic Curve Verifier. + * @dev P-256 verifier contract that follows the EIP-7212 EC verify precompile interface. For more + * details, refer to the EIP-7212 specification: + * @custom:security-contact bounty@safe.global + */ +interface IP256Verifier { + /** + * @notice A fallback function that takes the following input format and returns a result + * indicating whether the signature is valid or not: + * - `input[ 0: 32]`: message + * - `input[ 32: 64]`: signature r + * - `input[ 64: 96]`: signature s + * - `input[ 96:128]`: public key x + * - `input[128:160]`: public key y + * + * The output is a Solidity ABI encoded boolean value indicating whether or not the signature is + * valid. Specifically, it returns 32 bytes with a value of `0x00..00` or `0x00..01` for an + * invalid or valid signature respectively. + * + * Note that this function does not follow the Solidity ABI format (in particular, it does not + * have a 4-byte selector), which is why it requires a fallback function and not regular + * Solidity function. Additionally, it has `view` function semantics, and is expected to be + * called with `STATICCALL` opcode. + * + * @param input The encoded input parameters. + * @return output The encoded signature verification result. + */ + fallback(bytes calldata input) external returns (bytes memory output); +} diff --git a/modules/passkey/contracts/interfaces/ISafe.sol b/modules/passkey/contracts/interfaces/ISafe.sol index 7f2d89f7..016a2ffc 100644 --- a/modules/passkey/contracts/interfaces/ISafe.sol +++ b/modules/passkey/contracts/interfaces/ISafe.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.8.0 <0.9.0; -interface ISafeSetup { +interface ISafe { function setup( address[] calldata _owners, uint256 _threshold, diff --git a/modules/passkey/contracts/interfaces/IWebAuthnVerifier.sol b/modules/passkey/contracts/interfaces/IWebAuthnVerifier.sol new file mode 100644 index 00000000..2ba86b4f --- /dev/null +++ b/modules/passkey/contracts/interfaces/IWebAuthnVerifier.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable payable-fallback */ +pragma solidity ^0.8.0; + +/** + * @title WebAuthn Verifier Interface + * @dev Interface for verifying WebAuthn signatures. + * @custom:security-contact bounty@safe.global + */ +interface IWebAuthnVerifier { + /** + * @dev Verifies a WebAuthn signature. + * @param authenticatorData The authenticator data. + * @param authenticatorFlags The authenticator flags. + * @param challenge The challenge. + * @param clientDataFields The client data fields. + * @param r The ECDSA signature's R component. + * @param s The ECDSA signature's S component. + * @param qx The x-coordinate of the public key. + * @param qy The y-coordinate of the public key. + * @return success Whether the signature is valid. + */ + function verifyWebAuthnSignature( + bytes calldata authenticatorData, + bytes1 authenticatorFlags, + bytes32 challenge, + bytes calldata clientDataFields, + uint256 r, + uint256 s, + uint256 qx, + uint256 qy + ) external view returns (bool success); + + /** + * @dev Verifies a WebAuthn signature allowing malleability. + * @param authenticatorData The authenticator data. + * @param authenticatorFlags The authenticator flags. + * @param challenge The challenge. + * @param clientDataFields The client data fields. + * @param r The ECDSA signature's R component. + * @param s The ECDSA signature's S component. + * @param qx The x-coordinate of the public key. + * @param qy The y-coordinate of the public key. + * @return success Whether the signature is valid. + */ + function verifyWebAuthnSignatureAllowMalleability( + bytes calldata authenticatorData, + bytes1 authenticatorFlags, + bytes32 challenge, + bytes calldata clientDataFields, + uint256 r, + uint256 s, + uint256 qx, + uint256 qy + ) external view returns (bool success); +} diff --git a/modules/passkey/contracts/libraries/ERC1271.sol b/modules/passkey/contracts/libraries/ERC1271.sol new file mode 100644 index 00000000..25d7fb28 --- /dev/null +++ b/modules/passkey/contracts/libraries/ERC1271.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.0; + +/** + * @title ERC-1271 Magic Values + * @dev Library that defines constants for ERC-1271 related magic values. + * @custom:security-contact bounty@safe.global + */ +library ERC1271 { + /** + * @notice ERC-1271 magic value returned on valid signatures. + * @dev Value is derived from `bytes4(keccak256("isValidSignature(bytes32,bytes)")`. + */ + bytes4 internal constant MAGIC_VALUE = 0x1626ba7e; + + /** + * @notice Legacy EIP-1271 magic value returned on valid signatures. + * @dev This value was used in previous drafts of the EIP-1271 standard, but replaced by + * {MAGIC_VALUE} in the final version. + * + * Value is derived from `bytes4(keccak256("isValidSignature(bytes,bytes)")`. + */ + bytes4 internal constant LEGACY_MAGIC_VALUE = 0x20c13b0b; +} diff --git a/modules/passkey/contracts/verifiers/IP256Verifier.sol b/modules/passkey/contracts/libraries/P256.sol similarity index 68% rename from modules/passkey/contracts/verifiers/IP256Verifier.sol rename to modules/passkey/contracts/libraries/P256.sol index 8850644d..2ba320a1 100644 --- a/modules/passkey/contracts/verifiers/IP256Verifier.sol +++ b/modules/passkey/contracts/libraries/P256.sol @@ -1,44 +1,15 @@ // SPDX-License-Identifier: LGPL-3.0-only -/* solhint-disable payable-fallback */ pragma solidity ^0.8.0; -/** - * @title P-256 Elliptic Curve Verifier. - * @dev P-256 verifier contract that follows the EIP-7212 EC verify precompile interface. For more - * details, refer to the EIP-7212 specification: - * @custom:security-contact bounty@safe.global - */ -interface IP256Verifier { - /** - * @notice A fallback function that takes the following input format and returns a result - * indicating whether the signature is valid or not: - * - `input[ 0: 32]`: message - * - `input[ 32: 64]`: signature r - * - `input[ 64: 96]`: signature s - * - `input[ 96:128]`: public key x - * - `input[128:160]`: public key y - * - * The output is a Solidity ABI encoded boolean value indicating whether or not the signature is - * valid. Specifically, it returns 32 bytes with a value of `0x00..00` or `0x00..01` for an - * invalid or valid signature respectively. - * - * Note that this function does not follow the Solidity ABI format (in particular, it does not - * have a 4-byte selector), which is why it requires a fallback function and not regular - * Solidity function. Additionally, it has `view` function semantics, and is expected to be - * called with `STATICCALL` opcode. - * - * @param input The encoded input parameters. - * @return output The encoded signature verification result. - */ - fallback(bytes calldata input) external returns (bytes memory output); -} +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; /** - * @title P-256 Elliptic Curve Verifier. - * @dev P-256 verifier contract that follows the EIP-7212 EC verify precompile interface. For more - * details, refer to the EIP-7212 specification: + * @title P-256 Elliptic Curve Verification Library. + * @dev Library P-256 verification with contracts that follows the EIP-7212 EC verify precompile + * interface. See + * @custom:security-contact bounty@safe.global */ -library P256VerifierLib { +library P256 { /** * @notice P-256 curve order n divided by 2 for the signature malleability check. * @dev By convention, non-malleable signatures must have an `s` value that is less than half of diff --git a/modules/passkey/contracts/libraries/WebAuthnFlags.sol b/modules/passkey/contracts/libraries/WebAuthnFlags.sol new file mode 100644 index 00000000..9564a79d --- /dev/null +++ b/modules/passkey/contracts/libraries/WebAuthnFlags.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.0; + +/** + * @title WebAuthn Authentication Data Flags + * @dev Library that defines constants for WebAuthn verification of the authenticator data. In + * particular, it defines constants representing user flags that are included in an attestation's + * authenticator data. + * @custom:security-contact bounty@safe.global + */ +library WebAuthnFlags { + /** + * @notice Flag indicating user presence (UP). + * @dev A test of user presence is a simple form of authorization gesture and technical process + * where a user interacts with an authenticator by (typically) simply touching it (other + * modalities may also exist), yielding a Boolean result. Note that this does not constitute + * user verification because a user presence test, by definition, is not capable of biometric + * recognition, nor does it involve the presentation of a shared secret such as a password or + * PIN. + * + * See . + */ + bytes1 internal constant USER_PRESENCE = 0x01; + + /** + * @notice Flag indicating user verification (UV). + * @dev The technical process by which an authenticator locally authorizes the invocation of the + * authenticatorMakeCredential and authenticatorGetAssertion operations. User verification MAY + * be instigated through various authorization gesture modalities; for example, through a touch + * plus pin code, password entry, or biometric recognition (e.g., presenting a fingerprint). The + * intent is to distinguish individual users. + * + * Note that user verification does not give the Relying Party a concrete identification of the + * user, but when 2 or more ceremonies with user verification have been done with that + * credential it expresses that it was the same user that performed all of them. The same user + * might not always be the same natural person, however, if multiple natural persons share + * access to the same authenticator. + * + * See . + */ + bytes1 internal constant USER_VERIFICATION = 0x04; +} diff --git a/modules/passkey/contracts/libraries/WebAuthnSignature.sol b/modules/passkey/contracts/libraries/WebAuthnSignature.sol new file mode 100644 index 00000000..f5fce503 --- /dev/null +++ b/modules/passkey/contracts/libraries/WebAuthnSignature.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity ^0.8.0; + +/** + * @title WebAuthn Signature Format + * @dev Library for reading the standard Safe WebAuthn signature format from calldata bytes. + * @custom:security-contact bounty@safe.global + */ +library WebAuthnSignature { + /** + * @notice The WebAuthn signature data format. + * @dev WebAuthn signatures are expected to be the ABI-encoded bytes of the following structure. + * @param authenticatorData The authenticator data from the WebAuthn credential assertion. + * @param clientDataFields The additional fields from the client data JSON. This is the comma + * separated fields as they appear in the client data JSON from the WebAuthn credential + * assertion after the leading {type} and {challenge} fields. + * @param r The ECDSA signature's R component. + * @param s The ECDSA signature's S component. + */ + struct Data { + bytes authenticatorData; + bytes clientDataFields; + uint256 r; + uint256 s; + } + + /** + * @notice Casts calldata bytes to a WebAuthn signature data structure. + * @param signature The calldata bytes of the WebAuthn signature. + * @return data A pointer to the signature data in calldata. + * @dev This method casts the dynamic bytes array to a signature calldata pointer without + * additional verification. This is not a security issue for the WebAuthn implementation, as any + * signature data that would be represented from an invalid `signature` value, could also be + * encoded by a valid one. It does, however, mean that callers into the WebAuthn signature + * verification implementation might not validate as much of the data that they pass in as they + * would expect, but we do not believe this to be an issue. + */ + function cast(bytes calldata signature) internal pure returns (Data calldata data) { + // solhint-disable-next-line no-inline-assembly + assembly ("memory-safe") { + data := signature.offset + } + } +} diff --git a/modules/passkey/contracts/test/BadP256Verfier.sol b/modules/passkey/contracts/test/BadP256Verfier.sol index 5c6ff4be..0c304c2b 100644 --- a/modules/passkey/contracts/test/BadP256Verfier.sol +++ b/modules/passkey/contracts/test/BadP256Verfier.sol @@ -3,7 +3,7 @@ /* solhint-disable payable-fallback */ pragma solidity ^0.8.0; -import {IP256Verifier} from "../verifiers/IP256Verifier.sol"; +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; contract BadP256Verifier is IP256Verifier { enum Behaviour { diff --git a/modules/passkey/contracts/test/TestP256VerifierLib.sol b/modules/passkey/contracts/test/TestP256Lib.sol similarity index 80% rename from modules/passkey/contracts/test/TestP256VerifierLib.sol rename to modules/passkey/contracts/test/TestP256Lib.sol index 62b693be..d1d5b503 100644 --- a/modules/passkey/contracts/test/TestP256VerifierLib.sol +++ b/modules/passkey/contracts/test/TestP256Lib.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; -import {IP256Verifier, P256VerifierLib} from "../verifiers/IP256Verifier.sol"; +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; +import {P256} from "../libraries/P256.sol"; -contract TestP256VerifierLib { - using P256VerifierLib for IP256Verifier; +contract TestP256Lib { + using P256 for IP256Verifier; function verifySignature( IP256Verifier verifier, diff --git a/modules/passkey/contracts/test/TestWebAuthnSignerFactory.sol b/modules/passkey/contracts/test/TestWebAuthnSignerFactory.sol index 6ef92be3..ab989550 100644 --- a/modules/passkey/contracts/test/TestWebAuthnSignerFactory.sol +++ b/modules/passkey/contracts/test/TestWebAuthnSignerFactory.sol @@ -2,7 +2,8 @@ /* solhint-disable one-contract-per-file */ pragma solidity ^0.8.0; -import {IP256Verifier, P256VerifierLib} from "../verifiers/IP256Verifier.sol"; +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; +import {P256} from "../libraries/P256.sol"; contract TestWebAuthnSignerFactory { function createSigner(address verifier, uint256 x, uint256 y) external returns (TestWebAuthnSigner signer) { @@ -11,7 +12,7 @@ contract TestWebAuthnSignerFactory { } contract TestWebAuthnSigner { - using P256VerifierLib for IP256Verifier; + using P256 for IP256Verifier; struct SignatureData { bytes authenticatorData; diff --git a/modules/passkey/contracts/verifiers/FCLP256Verifier.sol b/modules/passkey/contracts/verifiers/FCLP256Verifier.sol index 95c33c46..a8491300 100644 --- a/modules/passkey/contracts/verifiers/FCLP256Verifier.sol +++ b/modules/passkey/contracts/verifiers/FCLP256Verifier.sol @@ -3,8 +3,8 @@ /* solhint-disable payable-fallback */ pragma solidity 0.8.24; +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; import {FCL_ecdsa} from "../vendor/FCL/FCL_ecdsa.sol"; -import {IP256Verifier} from "./IP256Verifier.sol"; /** * @title P-256 Elliptic Curve Verifier Based on The FreshCryptoLib P-256 Implementation. @@ -14,7 +14,7 @@ contract FCLP256Verifier is IP256Verifier { /** * @inheritdoc IP256Verifier */ - fallback(bytes calldata input) external returns (bytes memory) { + fallback(bytes calldata input) external returns (bytes memory output) { if (input.length != 160) { return abi.encodePacked(uint256(0)); } @@ -34,6 +34,6 @@ contract FCLP256Verifier is IP256Verifier { y := calldataload(128) } - return abi.encode(FCL_ecdsa.ecdsa_verify(message, r, s, x, y)); + output = abi.encode(FCL_ecdsa.ecdsa_verify(message, r, s, x, y)); } } diff --git a/modules/passkey/contracts/verifiers/WebAuthnVerifier.sol b/modules/passkey/contracts/verifiers/WebAuthnVerifier.sol index 1b3c7a51..be45c783 100644 --- a/modules/passkey/contracts/verifiers/WebAuthnVerifier.sol +++ b/modules/passkey/contracts/verifiers/WebAuthnVerifier.sol @@ -1,77 +1,11 @@ // SPDX-License-Identifier: LGPL-3.0-only -/* solhint-disable one-contract-per-file */ pragma solidity >=0.8.0; -import {IP256Verifier, P256VerifierLib} from "./IP256Verifier.sol"; +import {IP256Verifier} from "../interfaces/IP256Verifier.sol"; +import {IWebAuthnVerifier} from "../interfaces/IWebAuthnVerifier.sol"; +import {P256} from "../libraries/P256.sol"; import {Base64Url} from "../vendor/FCL/utils/Base64Url.sol"; -/** - * @title WebAuthnConstants - * @dev Library that defines constants for WebAuthn verification. - */ -library WebAuthnConstants { - /** - * @dev Constants representing the flags in the authenticator data of a WebAuthn verification. - * - * - `AUTH_DATA_FLAGS_UP`: User Presence (UP) flag in the authenticator data. - * - `AUTH_DATA_FLAGS_UV`: User Verification (UV) flag in the authenticator data. - * - `AUTH_DATA_FLAGS_BE`: Attested Credential Data (BE) flag in the authenticator data. - * - `AUTH_DATA_FLAGS_BS`: Extension Data (BS) flag in the authenticator data. - */ - bytes1 internal constant AUTH_DATA_FLAGS_UP = 0x01; - bytes1 internal constant AUTH_DATA_FLAGS_UV = 0x04; - bytes1 internal constant AUTH_DATA_FLAGS_BE = 0x08; - bytes1 internal constant AUTH_DATA_FLAGS_BS = 0x10; -} - -/** - * @title IWebAuthnVerifier - * @dev Interface for verifying WebAuthn signatures. - */ -interface IWebAuthnVerifier { - /** - * @dev Verifies a WebAuthn signature allowing malleability. - * @param authenticatorData The authenticator data. - * @param authenticatorFlags The authenticator flags. - * @param challenge The challenge. - * @param clientDataFields The client data fields. - * @param rs The signature components. - * @param qx The x-coordinate of the public key. - * @param qy The y-coordinate of the public key. - * @return A boolean indicating whether the signature is valid. - */ - function verifyWebAuthnSignatureAllowMalleability( - bytes calldata authenticatorData, - bytes1 authenticatorFlags, - bytes32 challenge, - bytes calldata clientDataFields, - uint256[2] calldata rs, - uint256 qx, - uint256 qy - ) external view returns (bool); - - /** - * @dev Verifies a WebAuthn signature. - * @param authenticatorData The authenticator data. - * @param authenticatorFlags The authenticator flags. - * @param challenge The challenge. - * @param clientDataFields The client data fields. - * @param rs The signature components. - * @param qx The x-coordinate of the public key. - * @param qy The y-coordinate of the public key. - * @return A boolean indicating whether the signature is valid. - */ - function verifyWebAuthnSignature( - bytes calldata authenticatorData, - bytes1 authenticatorFlags, - bytes32 challenge, - bytes calldata clientDataFields, - uint256[2] calldata rs, - uint256 qx, - uint256 qy - ) external view returns (bool); -} - /** * @title WebAuthnVerifier * @dev A contract that implements a WebAuthn signature verification following the precompile's interface. @@ -86,8 +20,11 @@ interface IWebAuthnVerifier { * * Both functions take the authenticator data, authenticator flags, challenge, client data fields, r and s components of the signature, and x and y coordinates of the public key as input. * The `verifyWebAuthnSignature` function also checks for signature malleability by ensuring that the s component is less than the curve order n/2. + * @custom:security-contact bounty@safe.global */ contract WebAuthnVerifier is IWebAuthnVerifier { + using P256 for IP256Verifier; + IP256Verifier internal immutable P256_VERIFIER; constructor(IP256Verifier verifier) { @@ -120,25 +57,18 @@ contract WebAuthnVerifier is IWebAuthnVerifier { } /** - * @dev Verifies the signature of a WebAuthn message using P256 elliptic curve, allowing for signature malleability. - * @param authenticatorData Authenticator data. - * @param authenticatorFlags Authenticator flags. - * @param challenge Challenge. - * @param clientDataFields Client data fields. - * @param rs R and S components of the signature. - * @param qx X coordinate of the public key. - * @param qy Y coordinate of the public key. - * @return result Whether the signature is valid. + * @inheritdoc IWebAuthnVerifier */ function verifyWebAuthnSignatureAllowMalleability( bytes calldata authenticatorData, bytes1 authenticatorFlags, bytes32 challenge, bytes calldata clientDataFields, - uint256[2] calldata rs, + uint256 r, + uint256 s, uint256 qx, uint256 qy - ) public view returns (bool result) { + ) public view returns (bool success) { // check authenticator flags, e.g. for User Presence (0x01) and/or User Verification (0x04) if ((authenticatorData[32] & authenticatorFlags) != authenticatorFlags) { return false; @@ -146,29 +76,22 @@ contract WebAuthnVerifier is IWebAuthnVerifier { bytes32 message = signingMessage(authenticatorData, challenge, clientDataFields); - result = P256VerifierLib.verifySignatureAllowMalleability(P256_VERIFIER, message, rs[0], rs[1], qx, qy); + success = P256_VERIFIER.verifySignatureAllowMalleability(message, r, s, qx, qy); } /** - * @dev Verifies the signature of a WebAuthn message using the P256 elliptic curve, checking for signature malleability. - * @param authenticatorData Authenticator data. - * @param authenticatorFlags Authenticator flags. - * @param challenge Challenge. - * @param clientDataFields Client data fields. - * @param rs R and S components of the signature. - * @param qx X coordinate of the public key. - * @param qy Y coordinate of the public key. - * @return result Whether the signature is valid. + * @inheritdoc IWebAuthnVerifier */ function verifyWebAuthnSignature( bytes calldata authenticatorData, bytes1 authenticatorFlags, bytes32 challenge, bytes calldata clientDataFields, - uint256[2] calldata rs, + uint256 r, + uint256 s, uint256 qx, uint256 qy - ) public view returns (bool result) { + ) public view returns (bool success) { // check authenticator flags, e.g. for User Presence (0x01) and/or User Verification (0x04) if ((authenticatorData[32] & authenticatorFlags) != authenticatorFlags) { return false; @@ -176,6 +99,6 @@ contract WebAuthnVerifier is IWebAuthnVerifier { bytes32 message = signingMessage(authenticatorData, challenge, clientDataFields); - result = P256VerifierLib.verifySignature(P256_VERIFIER, message, rs[0], rs[1], qx, qy); + success = P256_VERIFIER.verifySignature(message, r, s, qx, qy); } } diff --git a/modules/passkey/test/verifiers/P256VerfierLib.spec.ts b/modules/passkey/test/libraries/P256.spec.ts similarity index 57% rename from modules/passkey/test/verifiers/P256VerfierLib.spec.ts rename to modules/passkey/test/libraries/P256.spec.ts index eee79b16..f9886819 100644 --- a/modules/passkey/test/verifiers/P256VerfierLib.spec.ts +++ b/modules/passkey/test/libraries/P256.spec.ts @@ -3,49 +3,49 @@ import { deployments, ethers } from 'hardhat' import { Account } from '../utils/p256' -describe('P256VerifierLib', function () { +describe('P256', function () { const setupTests = deployments.createFixture(async ({ deployments }) => { const { FCLP256Verifier } = await deployments.fixture() const verifier = await ethers.getContractAt('FCLP256Verifier', FCLP256Verifier.address) - const P256VerifierLib = await ethers.getContractFactory('TestP256VerifierLib') - const verifierLib = await P256VerifierLib.deploy() + const P256Lib = await ethers.getContractFactory('TestP256Lib') + const p256Lib = await P256Lib.deploy() const account = new Account() - return { verifier, verifierLib, account } + return { verifier, p256Lib, account } }) it('Should return true on valid signature', async function () { - const { verifier, verifierLib, account } = await setupTests() + const { verifier, p256Lib, account } = await setupTests() const message = ethers.id('hello world') const { r, s } = account.sign(message) const { x, y } = account.publicKey - expect(await verifierLib.verifySignature(verifier, message, r, s, x, y)).to.be.true + expect(await p256Lib.verifySignature(verifier, message, r, s, x, y)).to.be.true }) it('Should return false on invalid signature', async function () { - const { verifier, verifierLib } = await setupTests() + const { verifier, p256Lib } = await setupTests() - expect(await verifierLib.verifySignature(verifier, ethers.ZeroHash, 1, 2, 3, 4)).to.be.false + expect(await p256Lib.verifySignature(verifier, ethers.ZeroHash, 1, 2, 3, 4)).to.be.false }) it('Should check for signature signature malleability', async function () { - const { verifier, verifierLib, account } = await setupTests() + const { verifier, p256Lib, account } = await setupTests() const message = ethers.id('hello world') const { r, highS } = account.sign(message) const { x, y } = account.publicKey - expect(await verifierLib.verifySignature(verifier, message, r, highS, x, y)).to.be.false - expect(await verifierLib.verifySignatureAllowMalleability(verifier, message, r, highS, x, y)).to.be.true + expect(await p256Lib.verifySignature(verifier, message, r, highS, x, y)).to.be.false + expect(await p256Lib.verifySignatureAllowMalleability(verifier, message, r, highS, x, y)).to.be.true }) it('Should return false for misbehaving verifiers', async function () { - const { verifierLib, account } = await setupTests() + const { p256Lib, account } = await setupTests() const message = ethers.id('hello world') const { r, s } = account.sign(message) @@ -58,8 +58,8 @@ describe('P256VerifierLib', function () { for (const behaviour of [WRONG_RETURNDATA_LENGTH, INVALID_BOOLEAN_VALUE, REVERT]) { const verifier = await BadP256Verifier.deploy(behaviour) - expect(await verifierLib.verifySignature(verifier, message, r, s, x, y)).to.be.false - expect(await verifierLib.verifySignatureAllowMalleability(verifier, message, r, s, x, y)).to.be.false + expect(await p256Lib.verifySignature(verifier, message, r, s, x, y)).to.be.false + expect(await p256Lib.verifySignatureAllowMalleability(verifier, message, r, s, x, y)).to.be.false } }) })