From 84f84e038aed634ce486931d9fe34bb693570c34 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Wed, 8 May 2024 15:43:21 +0200 Subject: [PATCH] Document the Safe Signer Launchpad As Experimental This PR moves the special 4337 integration contracts to an experimental folder and adds documentation specific to those contracts there (as well the rationale for the contracts being experimental in the first place). To follow up this PR, I will add unit tests for how we intend passkeys to be used over ERC-4337 (i.e. the "non-experimental" way of using them). --- modules/passkey/README.md | 80 ++----- .../contracts/4337/experimental/README.md | 211 ++++++++++++++++++ .../SafeSignerLaunchpad.sol | 6 +- .../SafeWebAuthnSharedSigner.sol | 6 +- .../{ => experimental}/Safe4337Module.spec.ts | 4 +- .../SafeSignerLaunchpad.spec.ts | 4 +- .../SafeWebAuthnSharedSigner.spec.ts | 6 +- .../SafeSignerLaunchpad.spec.ts | 4 +- .../SafeWebAuthnSharedSigner.spec.ts | 4 +- 9 files changed, 244 insertions(+), 81 deletions(-) create mode 100644 modules/passkey/contracts/4337/experimental/README.md rename modules/passkey/contracts/4337/{ => experimental}/SafeSignerLaunchpad.sol (98%) rename modules/passkey/contracts/4337/{ => experimental}/SafeWebAuthnSharedSigner.sol (97%) rename modules/passkey/test/4337/{ => experimental}/Safe4337Module.spec.ts (99%) rename modules/passkey/test/4337/{ => experimental}/SafeSignerLaunchpad.spec.ts (99%) rename modules/passkey/test/4337/{ => experimental}/SafeWebAuthnSharedSigner.spec.ts (98%) rename modules/passkey/test/4337/local-bundler/{ => experimental}/SafeSignerLaunchpad.spec.ts (98%) rename modules/passkey/test/4337/local-bundler/{ => experimental}/SafeWebAuthnSharedSigner.spec.ts (98%) diff --git a/modules/passkey/README.md b/modules/passkey/README.md index 6fa1bd711..f77c6cbdb 100644 --- a/modules/passkey/README.md +++ b/modules/passkey/README.md @@ -2,7 +2,12 @@ This package contains a passkey signature verifier, that can be used as an owner for a Safe, compatible with versions 1.3.0+. -## Contracts overview +Passkey support with the Safe is provided by implementing [`SignatureValidator`s](./contracts/base/SignatureValidator.sol) that can verify WebAuthn signatures on-chain, the underlying standard used by passkeys, and be used as owners for Safe accounts. At a high level, this works by: + +1. Deploying a signer instance using the [SafeWebAuthnSignerFactory](./contracts/SafeWebAuthnSignerFactory.sol), this will create a contract instance at a deterministic address using `CREATE2` based the parameters of the WebAuthn credential: the public key coordinates and which `ecverify` implementations to use. +2. Set the deployed signer as an owner for a Safe. + +## Contracts Overview Safe account being standard agnostic, new user flows such as custom signature verification logic can be added/removed as and when required. By leveraging this flexibility to support customizing Safe account, Passkeys-based execution flow can be enabled on a Safe. The contracts in this package use [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) standard and [WebAuthn](https://w3c.github.io/webauthn/) standard to allow signature verification for WebAuthn credentials using the secp256r1 curve. The contracts in this package are designed to be used with precompiles for signature verification in the supported networks or use any verifier contract as a fallback mechanism. In their current state, the contracts are tested with [Fresh Crypto Lib (FCL)](https://github.com/rdubois-crypto/FreshCryptoLib) and [daimo-eth](https://github.com/daimo-eth/p256-verifier). @@ -39,71 +44,18 @@ bytes memory signature = abi.encode(authenticatorData, clientDataFields, r, s); ### [P256](./contracts/libraries/P256.sol) -`P256` is a library for P256 signature verification with contracts that follows the EIP-7212 EC verify precompile interface. This library defines a custom type `Verifiers`, which encodes two addresses into a single `uint176`. The first address (2 bytes) is a precompile address dedicated to verification, and the second (20 bytes) is a fallback address. This setup allows the library to support networks where the precompile is not yet available, seamlessly transitioning to the precompile when it becomes active, while relying on a fallback contract address in the meantime. - -## Setup and Execution flow - -```mermaid -sequenceDiagram -actor U as User -participant CS as CredentialStore -actor B as Bundler -participant EP as EntryPoint -participant SPF as SafeProxyFactory -participant SWASPF as SafeWebAuthnSignerFactory -participant SP as SafeProxy -participant SSL as SafeSignerLaunchpad -participant S as Singleton -participant M as Module -participant SWASS as SafeWebAuthnSignerSingleton -participant WAV as WebAuthn library -participant PV as P256Verifier -actor T as Target - -U->>+CS: Create Credential (User calls `create(...)`) -CS->>U: Decode public key from the return value -U->>+SWASPF: Get signer address (signer might not be deployed yet) -SWASPF->>U: Signer address -U->>+B: Submit UserOp payload that deploys SafeProxy address with SafeSignerLaunchpad as singleton in initCode and corresponding call data that calls `initializeThenUserOp(...)` ands sets implementation to Safe Singleton - -B->>+EP: Submit User Operations -EP->>+SP: Validate UserOp -SP-->>SSL: Load SignerLaunchpad logic -SSL-->>SWASPF: Forward validation -SWASPF-->>SWASS: call isValidSignature(bytes32,bytes) with x,y values and verifier address added to the call data -SWASS-->>WAV: call verifyWebAuthnSignatureAllowMalleability -WAV->>+PV: Verify signature -PV->>WAV: Signature verification result -WAV->>SWASS: Signature verification result -SWASS->>SWASPF: Signature verification result -SWASPF-->>SSL: Return magic value - opt Pay required fee - SP->>EP: Perform fee payment - end -SP-->>-EP: Validation response - -EP->>+SP: Execute User Operation with call to `initializeThenUserOp(...)` -SP-->>SSL: Load SignerLaunchpad logic -SP->>+SWASPF: Create Signer -SWASPF-->>SP: Return owner address -SP->>SP: Setup Safe -SP-->>SP: delegatecall with calldata received in `initializeThenUserOp(...)` -SP-->>S: Load Safe logic -SP->>+M: Forward execution -M->>SP: Execute From Module -SP-->>S: Load Safe logic -SP->>+T: Perform transaction - opt Bubble up return data - T-->>-SP: Call Return Data - SP-->>M: Call Return Data - M-->>-SP: Call return data - SP-->>-EP: Call return data - end -``` +`P256` is a library for P256 signature verification with contracts that follows the EIP-7212 EC verify precompile interface. This library defines a custom type `Verifiers`, which encodes two addresses into a single `uint176`. The first address (2 bytes) is a precompile address dedicated to verification, and the second (20 bytes) is a fallback address. This setup allows the library to support networks where the precompile is not yet available, seamlessly transitioning to the precompile when it becomes active, while relying on a fallback contract address in the meantime. Note that only 2 bytes are needed to represent the precompile address, as the reserved range for precompile contracts is between address 0x0000 and 0xffff which fits into 2 bytes. -ERC-4337 outlines specific storage access rules for the validation phase, which limits the deployment of SafeProxy for use with the passkey flow. To navigate this restriction, in the `initCode` of UserOp, a `SafeProxy` is deployed with `SafeSignerLaunchpad` as a singleton. The `SafeSignerLaunchpad` is used to validate the signature of the UserOp. The `SafeSignerLaunchpad` forwards the signature validation to the `SafeWebAuthnSignerSingleton`, which in turn forwards the signature validation to the `WebAuthn` library. `WebAuthn` forwards the call to `P256Verifier`. The `P256Verifier` is used to validate the signature. In the validation, phase the launchpad stores the Safe's setup hash (owners, threshold, modules, etc) which is then verified during the execution phase. +The `verifiers` value can be computed with the following code: -During the execution phase, the implementation of the `SafeProxy` is set to the Safe Singleton along with the owner as signer contract deployed by SafeSignerLaunchpad. +```solidity +uint16 precompile = ...; +address fallbackVerifier = ...; + +P256.Verifiers = P256.Verifiers.wrap( + (uint176(precompile) << 160) + uint176(uint160(fallbackVerifier)) +); +``` ## Usage diff --git a/modules/passkey/contracts/4337/experimental/README.md b/modules/passkey/contracts/4337/experimental/README.md new file mode 100644 index 000000000..6fe28d034 --- /dev/null +++ b/modules/passkey/contracts/4337/experimental/README.md @@ -0,0 +1,211 @@ +# Passkey 4337 Support + +This directory contains additional support contracts for using passkeys with Safes over ERC-4337. + +> These contracts are marked as experimental as they are only needed when deploying Safes with initial passkey owners that are required for verifying the very first ERC-4337 user operation with `initCode`. We do not, however, recommend this as it would tie your Safe account's address to a passkey which may not be always available. In particular: the WebAuthn authenticator that stores a device-bound credential that does not allow for backups may be lost, the domain the credential is tied to may no longer be available, you lose access to the passkey provider where your WebAuthn credentials are stored (for example, you no longer have an iPhone or MacBook with access to your iCloud keychain passkeys). +> +> As such, for the moment, we recommend that Safes be created with an ownership structure or recovery mechanism that allows passkey owners to be rotated in case access to the WebAuthn credential is lost. + +## Overview + +The core contract provided by the `passkey` module is the `SafeWebAuthnSignerFactory` contract which can be used to create smart contract signers that can be used as owners of Safes. These WebAuthn signers are fully supported both with traditional Safe transactions and infrastructure, as well as ERC-4337. In fact, they are designed such that no storage is read during signature verification (all configuration - the WebAuthn credential public key coordinates and the P-256 verifier contract to use) are stored in contract code instead of account storage for compatibility with ERC-4337. + +There is one notable caveat when using the `passkey` module with ERC-4337 specifically, which is that ERC-4337 user operations can only deploy exactly one `CREATE2` contract whose address matches the `sender` of the user operation. This means that deploying both the Safe account and its WebAuthn credential owner in a user operation's `initCode` is not possible. + +In order to work around this limitation, there are two possible workarounds that can be used: + +1. Using a "launchpad" contract, the `SafeSignerLaunchpad`: this implementation provides an alternative `singleton` implementation for the account that is used **only** for the first user operation and makes use of a `ISafeSignerFactory` to validate the WebAuthn signature without deploying the owner in the validation phase of the ERC-4337 user operation (i.e. `validateUserOp`). The WebAuthn owner is then deployed in the execution phase of the user operation, once there are no more restrictions on what is allowed to execute. This implementation allows for 1/1 Safes with a single passkey owner to be able to execute transactions over ERC-4337. +2. Using a shared signer, the `SafeWebAuthnSharedSigner`: this implementation provides a shared signer that can be used as a Safe owner. The shared signer uses account storage for its configuration in order to circumvent any ERC-4337 restrictions on storage during `initCode`. This implementation allows for n/m (including 1/1) Safes with a single passkey owner to be able to execute transactions over ERC-4337. Note that since the signer is a single contract, it can only be used to represent a single passkey owner for any given Safe; however, additional passkey owners can still be added by using the `SafeWebAuthnSignerFactory` to deploy additional WebAuthn signer contracts and adding them as owners to the Safe. + +Note that this restriction only applies if **you want to use the passkey module with a Safe over 4337 without any additional EOA owners**. If _any_ of the following applies to you, then the contracts provided in this directory are **not** required: + +- You want to deploy a Safe that is also owned by more than `threshold` additional EOA signers, in this case you can use the EOAs to sign the first ERC-4337 user operation that deploys the account and include in the execution phase a call to the `SafeWebAuthnSignerFactory` to deploy the passkey owner. +- You want to deploy the Safe outside of ERC-4337, the WebAuthn signer instance as well as the Safe account can be deployed permissionlessly, so their creation can be batched together in a single transaction when deploying the Safe. Once the Safe and the WebAuthn signer are deployed, they can be used regularly over ERC-4337. +- The passkey owner is already deployed, in this case, the standard ERC-4337 deployment process would apply where you would simply add the already created WebAuthn signer instance as an owner to the Safe. + +## [Safe Signer Launchpad](./SafeSignerLaunchpad.sol) + +The Safe signer launchpad is used as a `singleton` implementation for the very first user operation. The signature check in the ERC-4337 validation phase is done **without** deploying the WebAuthn signer for the passkey credential using a well-defined `ISafeSignerFactory` interface. In the case the user operation is validated and then executed, the launchpad will: + +1. Set the `singleton` to the actual Safe implementation to use +2. Deploy the WebAuthn signer, so that it can be used normally over ERC-4337 for the following user operations + +Note that for the very first user operation, an EIP-712 `SafeInitOp` is signed instead of the usual `SafeOp` that is used by the canonical ERC-4337 module. This is done in order to distinguish signatures of a launchpad Safe's user operation from a standard ERC-4337 Safe user operation. + +### Init Code Example + +The `initCode` should be generated with: + +```solitidy +SafeProxyFactory proxyFactory = ...; +SafeSignerLaunchpad launchpad = ...; +Safe singleton = ...; +SafeWebAuthnSignerFactory signerFactory = ...; + +uint256 signerX = ...; +uint256 signerY = ...; +uint256 signerVerifiers = ...; + +address initializer = ...; +bytes memory initializerData = ...; +address fallbackHandler = ...; + +bytes memory initCode = abi.encodePacked( + proxyFactory, + abi.encodeCall( + launchpad.setup, + ( + address(singleton), + address(signerFactory), + signerX, + signerY, + signerVerifiers, + initializer, + initializerData, + fallbackHandler + ) + ) +); +``` + +### User Operation Execution Flow + +```mermaid +sequenceDiagram + participant CS as Browser + actor U as User + actor B as Bundler + participant EP as EntryPoint + participant SPF as SafeProxyFactory + participant SP as SafeProxy + participant SSL as SafeSignerLaunchpad + participant S as Safe + participant SWASF as SafeWebAuthnSignerFactory + participant SWASP as SafeWebAuthnSignerProxy + participant SWASS as SafeWebAuthnSignerSingleton + participant WAV as WebAuthn library + participant PV as P256Verifier + actor T as Target + + U->>+CS: Create Credential (User calls `navigator.credentials.create(...)`) + CS->>U: Decode public key from the return value + U->>SWASF: Get signer address (signer might not be deployed yet) + SWASF->>U: Signer address + U->>+B: Submit UserOp with `initCode` to deploy a SafeProxy with SafeSignerLaunchpad as singleton + + note over EP: account creation + B->>+EP: handleOps([userOp], ...) + EP->>+SPF: createProxyWithNonce(launchpad, setup, ...) + SPF->>SP: CREATE2 + SPF->>SP: setup(...) + SP-->>SSL: DELEGATECALL + SP->>S: DELEGATECALL setup(...) + S-->>SPF: ok + SPF-->>-EP: Proxy address + + note over EP: validation phase + EP->>+SP: validateUserOp(...) + SP-->>SSL: DELEGATECALL + SP->>SWASF: isValidSignatureForSigner(...) + SWASF->>SWASS: isValidSignature(...) || configuration + SWASS->>WAV: verifyWebAuthnSignatureAllowMalleability(...) + WAV->>PV: ecverify(...) + PV-->>WAV: Signature verification result + WAV-->>SWASS: Signature verification result + SWASS-->>SWASF: Signature verification result + SWASF-->>SP: ERC-1271 magic value + opt Pay required fee + SP->>EP: Perform fee payment + end + SP-->>-EP: Validation response + + note over EP: execution phase + EP->>+SP: promoteAccountAndExecuteUserOp(...) + SP-->>SSL: DELEGATECALL + SP->>SP: set Safe as singleton + SP->>SWASF: createSigner(...) + SP->>T: Execute user operation + T-->>SP: Result + SP-->>-EP: Result +``` + +## [Safe WebAuthn Shared Signer](./SafeWebAuthnSharedSigner.sol) + +Alternatively, the shared signer can be used in order as an owner for the Safe. This method is simpler than the launchpad, in that there is no special setup step, and the standard Safe implementation and canonical ERC-4337 module can be used. The only additional requirement is that the Safe `setup` must delegate call into the `SafeWebAuthnSharedSigner` instance in order for it to set its configuration. When paired with the `Safe4337Module`, the `MultiSend` contract can be used to both enable the ERC-4337 support in the Safe as well as configure the WebAuthn credential in the WebAuthn shared signer. + +Because the shared signer is a single contract address, it can only ever represent a single passkey owner for Safe. However, additional passkey owners can be added for sWebAuthn signers created with the canonical `SafeWebAuthnSignerFactory` contract, and can even co-exist with the `SafeWebAuthnSharedSigner` owner (so there is no need to re-deploy a signer for the original WebAuthn credential represented by the shared signer). + +### Init Code Example + +The `initCode` should be generated with: + +```solitidy +SafeProxyFactory proxyFactory = ...; +Safe singleton = ...; +SafeWebAuthnSharedSigner sharedSigner = ...; +Safe4337Module safe4337Module = ...; +SafeModuleSetup moduleSetup = ...; +MultiSend multiSend = ...; + +uint256 signerX = ...; +uint256 signerY = ...; +uint256 signerVerifiers = ...; + +address initializer = ...; +bytes memory initializerData = ...; +address fallbackHandler = ...; + +address[] owners memory = [..., address(sharedSigner), ...]; +uint256 threshold = ...; + +bytes memory configureData = abi.encodeCall( + sharedSigner.configure, + ( + signerX, + signerY, + signerVerifiers + ) +); + +address[] memory modules = new address[](1); +{ + modules[0] = safe4337Module; +} +bytes memory enableModulesData = abi.encodeCall( + moduleSetup.enableModules, + (modules) +); + +bytes memory initCode = abi.encodePacked( + proxyFactory, + abi.encodeCall( + launchpad.setup, + ( + owners, + threshold, + address(multiSend), + abi.encodeCall( + multiSend.multiSend, + abi.encodePacked( + // configure signer + uint8(1), // operation + address(sharedSigner), + uint256(0), // value + configureData.length, + configureData + // enable modules + uint8(1), // operation + address(moduleSetup), + uint256(0), // value + enableModulesData.length, + enableModulesData + ) + ), + address(safe4337Module), + address(0), + 0, + address(0) + ) + ) +); +``` diff --git a/modules/passkey/contracts/4337/SafeSignerLaunchpad.sol b/modules/passkey/contracts/4337/experimental/SafeSignerLaunchpad.sol similarity index 98% rename from modules/passkey/contracts/4337/SafeSignerLaunchpad.sol rename to modules/passkey/contracts/4337/experimental/SafeSignerLaunchpad.sol index 22067d7e7..030b34c66 100644 --- a/modules/passkey/contracts/4337/SafeSignerLaunchpad.sol +++ b/modules/passkey/contracts/4337/experimental/SafeSignerLaunchpad.sol @@ -6,9 +6,9 @@ import {PackedUserOperation} from "@account-abstraction/contracts/interfaces/Pac import {_packValidationData} from "@account-abstraction/contracts/core/Helpers.sol"; import {SafeStorage} from "@safe-global/safe-contracts/contracts/libraries/SafeStorage.sol"; -import {ISafeSignerFactory, P256} from "../interfaces/ISafeSignerFactory.sol"; -import {ISafe} from "../interfaces/ISafe.sol"; -import {ERC1271} from "../libraries/ERC1271.sol"; +import {ISafeSignerFactory, P256} from "../../interfaces/ISafeSignerFactory.sol"; +import {ISafe} from "../../interfaces/ISafe.sol"; +import {ERC1271} from "../../libraries/ERC1271.sol"; /** * @title Safe Launchpad for Custom ECDSA Signing Schemes. diff --git a/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol b/modules/passkey/contracts/4337/experimental/SafeWebAuthnSharedSigner.sol similarity index 97% rename from modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol rename to modules/passkey/contracts/4337/experimental/SafeWebAuthnSharedSigner.sol index 2d1bd4090..de5eec21e 100644 --- a/modules/passkey/contracts/4337/SafeWebAuthnSharedSigner.sol +++ b/modules/passkey/contracts/4337/experimental/SafeWebAuthnSharedSigner.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.8.0; -import {SignatureValidator} from "../base/SignatureValidator.sol"; -import {ISafe} from "../interfaces/ISafe.sol"; -import {P256, WebAuthn} from "../libraries/WebAuthn.sol"; +import {SignatureValidator} from "../../base/SignatureValidator.sol"; +import {ISafe} from "../../interfaces/ISafe.sol"; +import {P256, WebAuthn} from "../../libraries/WebAuthn.sol"; /** * @title Safe WebAuthn Shared Signer diff --git a/modules/passkey/test/4337/Safe4337Module.spec.ts b/modules/passkey/test/4337/experimental/Safe4337Module.spec.ts similarity index 99% rename from modules/passkey/test/4337/Safe4337Module.spec.ts rename to modules/passkey/test/4337/experimental/Safe4337Module.spec.ts index 8a3831b1b..afc1864d3 100644 --- a/modules/passkey/test/4337/Safe4337Module.spec.ts +++ b/modules/passkey/test/4337/experimental/Safe4337Module.spec.ts @@ -9,8 +9,8 @@ import { } from '@safe-global/safe-4337/src/utils/userOp' import { chainId, encodeMultiSendTransactions } from '@safe-global/safe-4337/test/utils/encoding' import { Safe4337 } from '@safe-global/safe-4337/src/utils/safe' -import { WebAuthnCredentials } from '../utils/webauthnShim' -import { decodePublicKey, encodeWebAuthnSignature } from '../../src/utils/webauthn' +import { WebAuthnCredentials } from '../../utils/webauthnShim' +import { decodePublicKey, encodeWebAuthnSignature } from '../../../src/utils/webauthn' describe('Safe4337Module', () => { const setupTests = deployments.createFixture(async ({ deployments }) => { diff --git a/modules/passkey/test/4337/SafeSignerLaunchpad.spec.ts b/modules/passkey/test/4337/experimental/SafeSignerLaunchpad.spec.ts similarity index 99% rename from modules/passkey/test/4337/SafeSignerLaunchpad.spec.ts rename to modules/passkey/test/4337/experimental/SafeSignerLaunchpad.spec.ts index 2b5e1c31e..b4e884ee2 100644 --- a/modules/passkey/test/4337/SafeSignerLaunchpad.spec.ts +++ b/modules/passkey/test/4337/experimental/SafeSignerLaunchpad.spec.ts @@ -2,8 +2,8 @@ import { setBalance } from '@nomicfoundation/hardhat-network-helpers' import { expect } from 'chai' import { deployments, ethers } from 'hardhat' -import { SafeSignerLaunchpad, PackedUserOperationStruct } from '../../typechain-types/contracts/4337/SafeSignerLaunchpad' -import * as ERC1271 from '../utils/erc1271' +import { SafeSignerLaunchpad, PackedUserOperationStruct } from '../../../typechain-types/contracts/4337/experimental/SafeSignerLaunchpad' +import * as ERC1271 from '../../utils/erc1271' describe('SafeSignerLaunchpad', () => { const setupTests = deployments.createFixture(async () => { diff --git a/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts b/modules/passkey/test/4337/experimental/SafeWebAuthnSharedSigner.spec.ts similarity index 98% rename from modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts rename to modules/passkey/test/4337/experimental/SafeWebAuthnSharedSigner.spec.ts index 2e8a474bb..7a5d957a2 100644 --- a/modules/passkey/test/4337/SafeWebAuthnSharedSigner.spec.ts +++ b/modules/passkey/test/4337/experimental/SafeWebAuthnSharedSigner.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai' import { deployments, ethers } from 'hardhat' -import * as ERC1271 from '../utils/erc1271' -import { DUMMY_AUTHENTICATOR_DATA, base64UrlEncode, getSignatureBytes } from '../../src/utils/webauthn' -import { encodeWebAuthnSigningMessage } from '../utils/webauthnShim' +import * as ERC1271 from '../../utils/erc1271' +import { DUMMY_AUTHENTICATOR_DATA, base64UrlEncode, getSignatureBytes } from '../../../src/utils/webauthn' +import { encodeWebAuthnSigningMessage } from '../../utils/webauthnShim' const SIGNER_STORAGE_SLOT = ethers.toBeHex(BigInt(ethers.id('SafeWebAuthnSharedSigner.signer')) - 3n, 32) diff --git a/modules/passkey/test/4337/local-bundler/SafeSignerLaunchpad.spec.ts b/modules/passkey/test/4337/local-bundler/experimental/SafeSignerLaunchpad.spec.ts similarity index 98% rename from modules/passkey/test/4337/local-bundler/SafeSignerLaunchpad.spec.ts rename to modules/passkey/test/4337/local-bundler/experimental/SafeSignerLaunchpad.spec.ts index 8a8e55c38..635513d8d 100644 --- a/modules/passkey/test/4337/local-bundler/SafeSignerLaunchpad.spec.ts +++ b/modules/passkey/test/4337/local-bundler/experimental/SafeSignerLaunchpad.spec.ts @@ -2,8 +2,8 @@ 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 '@safe-global/safe-4337-local-bundler' -import { WebAuthnCredentials } from '../../utils/webauthnShim' -import { decodePublicKey, encodeWebAuthnSignature } from '../../../src/utils/webauthn' +import { WebAuthnCredentials } from '../../../utils/webauthnShim' +import { decodePublicKey, encodeWebAuthnSignature } from '../../../../src/utils/webauthn' describe('WebAuthn Signer Launchpad [@4337]', () => { before(function () { diff --git a/modules/passkey/test/4337/local-bundler/SafeWebAuthnSharedSigner.spec.ts b/modules/passkey/test/4337/local-bundler/experimental/SafeWebAuthnSharedSigner.spec.ts similarity index 98% rename from modules/passkey/test/4337/local-bundler/SafeWebAuthnSharedSigner.spec.ts rename to modules/passkey/test/4337/local-bundler/experimental/SafeWebAuthnSharedSigner.spec.ts index 503ccef33..76daa902e 100644 --- a/modules/passkey/test/4337/local-bundler/SafeWebAuthnSharedSigner.spec.ts +++ b/modules/passkey/test/4337/local-bundler/experimental/SafeWebAuthnSharedSigner.spec.ts @@ -8,8 +8,8 @@ import { buildRpcUserOperationFromSafeUserOperation, } from '@safe-global/safe-4337/src/utils/userOp' import { buildSignatureBytes } from '@safe-global/safe-4337/src/utils/execution' -import { WebAuthnCredentials } from '../../utils/webauthnShim' -import { decodePublicKey, encodeWebAuthnSignature } from '../../../src/utils/webauthn' +import { WebAuthnCredentials } from '../../../utils/webauthnShim' +import { decodePublicKey, encodeWebAuthnSignature } from '../../../../src/utils/webauthn' describe('WebAuthn Singleton Signers [@4337]', () => { before(function () {