diff --git a/.github/workflows/ci_examples.yml b/.github/workflows/ci_passkey_example.yml
similarity index 82%
rename from .github/workflows/ci_examples.yml
rename to .github/workflows/ci_passkey_example.yml
index c0fa7118..397ab434 100644
--- a/.github/workflows/ci_examples.yml
+++ b/.github/workflows/ci_passkey_example.yml
@@ -1,5 +1,10 @@
-name: safe-modules-examples
-on: [push]
+name: safe-modules-4337-passkey-example
+on:
+ push:
+ paths:
+ - 'modules/4337/**'
+ - 'modules/passkey/**'
+ - 'examples/safe-4337-passkeys/**'
jobs:
checks:
diff --git a/examples/safe-4337-passkeys/src/App.tsx b/examples/safe-4337-passkeys/src/App.tsx
index 3cedd75a..4701b6ee 100644
--- a/examples/safe-4337-passkeys/src/App.tsx
+++ b/examples/safe-4337-passkeys/src/App.tsx
@@ -6,7 +6,7 @@ import ConnectButton from './components/ConnectButton.tsx'
import { useState } from 'react'
import { useWeb3ModalProvider, useWeb3ModalAccount } from '@web3modal/ethers/react'
import { APP_CHAIN_ID } from './config.ts'
-import { switchToMumbai } from './logic/wallets.ts'
+import { switchToSepolia } from './logic/wallets.ts'
import { PasskeyCard } from './components/PasskeyCard.tsx'
import { SafeCard } from './components/SafeCard.tsx'
@@ -34,17 +34,17 @@ function App() {
}
}
- const handleSwitchToMumbaiClick = () => {
+ const handleSwitchToSepoliaClick = () => {
if (!walletProvider) return
setError(undefined)
try {
- switchToMumbai(walletProvider)
+ switchToSepolia(walletProvider)
} catch (error) {
if (error instanceof Error) {
setError(error.message)
} else {
- setError('Unknown error when switching to Mumbai network')
+ setError('Unknown error when switching to Ethereum Sepolia test network')
}
}
}
@@ -72,8 +72,8 @@ function App() {
if (connectedToWrongChain) {
content = (
-
Please switch to Mumbai network to continue
-
+
Please switch to Ethereum Sepolia test network to continue
+
)
}
diff --git a/examples/safe-4337-passkeys/src/components/SafeCard.tsx b/examples/safe-4337-passkeys/src/components/SafeCard.tsx
index e7c1e393..f8a1a02e 100644
--- a/examples/safe-4337-passkeys/src/components/SafeCard.tsx
+++ b/examples/safe-4337-passkeys/src/components/SafeCard.tsx
@@ -1,17 +1,23 @@
import { useMemo, useState } from 'react'
import { ethers } from 'ethers'
-import { encodeAddModuleLibCall } from '../logic/safe'
+import { encodeSafeModuleSetupCall } from '../logic/safe'
import type { SafeInitializer } from '../logic/safe'
import {
- ADD_MODULES_LIB_ADDRESS,
SAFE_4337_MODULE_ADDRESS,
+ SAFE_MODULE_SETUP_ADDRESS,
SAFE_PROXY_FACTORY_ADDRESS,
SAFE_SINGLETON_ADDRESS,
WEBAUTHN_SIGNER_FACTORY_ADDRESS,
WEBAUTHN_VERIFIER_ADDRESS,
} from '../config'
import { PasskeyLocalStorageFormat } from '../logic/passkeys'
-import { UnsignedUserOperation, getRequiredPrefund, prepareUserOperationWithInitialisation, signAndSendUserOp } from '../logic/userOp'
+import {
+ UnsignedPackedUserOperation,
+ getRequiredPrefund,
+ packGasParameters,
+ prepareUserOperationWithInitialisation,
+ signAndSendUserOp,
+} from '../logic/userOp'
import { useUserOpGasLimitEstimation } from '../hooks/useUserOpGasEstimation'
import { RequestStatus } from '../utils'
import { PrefundCard } from './OpPrefundCard'
@@ -29,8 +35,8 @@ function SafeCard({ passkey, provider }: { passkey: PasskeyLocalStorageFormat; p
['uint256', 'uint256', 'address'],
[passkey.pubkeyCoordinates.x, passkey.pubkeyCoordinates.y, WEBAUTHN_VERIFIER_ADDRESS],
),
- setupTo: ADD_MODULES_LIB_ADDRESS,
- setupData: encodeAddModuleLibCall([SAFE_4337_MODULE_ADDRESS]),
+ setupTo: SAFE_MODULE_SETUP_ADDRESS,
+ setupData: encodeSafeModuleSetupCall([SAFE_4337_MODULE_ADDRESS]),
}),
[passkey.pubkeyCoordinates.x, passkey.pubkeyCoordinates.y],
)
@@ -64,13 +70,15 @@ function SafeCard({ passkey, provider }: { passkey: PasskeyLocalStorageFormat; p
const handleDeploySafeClick = async () => {
if (!gasParametersReady) return
- const userOpToSign: UnsignedUserOperation = {
+ const userOpToSign: UnsignedPackedUserOperation = {
...unsignedUserOperation,
- verificationGasLimit: userOpGasLimitEstimation.verificationGasLimit,
+ ...packGasParameters({
+ verificationGasLimit: userOpGasLimitEstimation.verificationGasLimit,
+ callGasLimit: userOpGasLimitEstimation.callGasLimit,
+ maxPriorityFeePerGas: feeData?.maxPriorityFeePerGas,
+ maxFeePerGas: feeData?.maxFeePerGas,
+ }),
preVerificationGas: userOpGasLimitEstimation.preVerificationGas,
- callGasLimit: userOpGasLimitEstimation.callGasLimit,
- maxFeePerGas: '0x' + feeData?.maxFeePerGas.toString(16),
- maxPriorityFeePerGas: '0x' + feeData?.maxPriorityFeePerGas.toString(16),
}
const bundlerUserOpHash = await signAndSendUserOp(userOpToSign, passkey)
@@ -84,14 +92,14 @@ function SafeCard({ passkey, provider }: { passkey: PasskeyLocalStorageFormat; p
{userOpHash && (
Your Safe is being deployed. Track the user operation on{' '}
- jiffyscan
+ jiffyscan
)}
{deployed && (
Your Safe has been deployed. More info on{' '}
- jiffyscan
+ jiffyscan
)}
diff --git a/examples/safe-4337-passkeys/src/config.ts b/examples/safe-4337-passkeys/src/config.ts
index 1e890309..fc6667be 100644
--- a/examples/safe-4337-passkeys/src/config.ts
+++ b/examples/safe-4337-passkeys/src/config.ts
@@ -1,17 +1,17 @@
-const APP_CHAIN_ID = 80001
+const APP_CHAIN_ID = 11155111
-/*
+/*
Some of the contracts used in the PoC app are still experimental, and not included in
the production deployment packages, thus we need to hardcode their addresses here.
Deployment commit: https://github.com/safe-global/safe-modules/commit/3853f34f31837e0a0aee47a4452564278f8c62ba
*/
-const SAFE_SIGNER_LAUNCHPAD_ADDRESS = '0xe208DFA2A62be117142d7054BE59034c39A56dBD'
+const SAFE_SIGNER_LAUNCHPAD_ADDRESS = '0x8a29BeF99755Cb8587189108d4D8D8f8247dB1B1'
-const SAFE_4337_MODULE_ADDRESS = '0x700ADDDa9D8D6fF3230016f1a0a81EA4d4615804'
+const SAFE_4337_MODULE_ADDRESS = '0xfaa6F2eC82BdA7C22220522869E854a3446053A5'
-const ADD_MODULES_LIB_ADDRESS = '0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47'
+const SAFE_MODULE_SETUP_ADDRESS = '0x2dd68b007B46fBe91B9A7c3EDa5A7a1063cB5b47'
-const WEBAUTHN_SIGNER_FACTORY_ADDRESS = '0xe59e5dDd6C5D98b2b4a9D2094639dD881e305Dc5'
+const WEBAUTHN_SIGNER_FACTORY_ADDRESS = '0x05234efAd657358b56Fbe05e38800179261F429C'
const WEBAUTHN_VERIFIER_ADDRESS = '0xCAc51aDF726E4b269645a7fD6a43296A1Ff53e8d'
@@ -19,12 +19,12 @@ const SAFE_PROXY_FACTORY_ADDRESS = '0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67'
const SAFE_SINGLETON_ADDRESS = '0x29fcB43b46531BcA003ddC8FCB67FFE91900C762'
-const ENTRYPOINT_ADDRESS = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'
+const ENTRYPOINT_ADDRESS = '0x0000000071727De22E5E9d8BAf0edAc6f37da032'
const XANDER_BLAZE_NFT_ADDRESS = '0xBb9ebb7b8Ee75CDBf64e5cE124731A89c2BC4A07'
export {
- ADD_MODULES_LIB_ADDRESS,
+ SAFE_MODULE_SETUP_ADDRESS,
APP_CHAIN_ID,
ENTRYPOINT_ADDRESS,
SAFE_SIGNER_LAUNCHPAD_ADDRESS,
diff --git a/examples/safe-4337-passkeys/src/hooks/useUserOpGasEstimation.ts b/examples/safe-4337-passkeys/src/hooks/useUserOpGasEstimation.ts
index d3c660e6..8be8d7b8 100644
--- a/examples/safe-4337-passkeys/src/hooks/useUserOpGasEstimation.ts
+++ b/examples/safe-4337-passkeys/src/hooks/useUserOpGasEstimation.ts
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
-import { UnsignedUserOperation, UserOpGasLimitEstimation, estimateUserOpGasLimit } from '../logic/userOp'
+import { UnsignedPackedUserOperation, UserOpGasLimitEstimation, estimateUserOpGasLimit } from '../logic/userOp'
import { RequestStatus } from '../utils'
/**
@@ -7,7 +7,7 @@ import { RequestStatus } from '../utils'
* @param userOp The unsigned user operation.
* @returns An object containing the user operation gas limit estimation and the request status.
*/
-function useUserOpGasLimitEstimation(userOp: UnsignedUserOperation) {
+function useUserOpGasLimitEstimation(userOp: UnsignedPackedUserOperation) {
const [userOpGasLimitEstimation, setUserOpGasLimitEstimation] = useState(undefined)
const [status, setStatus] = useState(RequestStatus.NOT_REQUESTED)
diff --git a/examples/safe-4337-passkeys/src/logic/safe.ts b/examples/safe-4337-passkeys/src/logic/safe.ts
index a5ca2a28..72eb315c 100644
--- a/examples/safe-4337-passkeys/src/logic/safe.ts
+++ b/examples/safe-4337-passkeys/src/logic/safe.ts
@@ -1,7 +1,7 @@
import { ethers } from 'ethers'
import { abi as SafeSignerLaunchpadAbi } from '@safe-global/safe-erc4337/build/artifacts/contracts/experimental/SafeSignerLaunchpad.sol/SafeSignerLaunchpad.json'
import { abi as WebAuthnSignerFactoryAbi } from '@safe-global/safe-erc4337/build/artifacts/contracts/experimental/WebAuthnSigner.sol/WebAuthnSignerFactory.json'
-import { abi as SetupModulesAbi } from '@safe-global/safe-erc4337/build/artifacts/contracts/SafeModuleSetup.sol/SafeModuleSetup.json'
+import { abi as SetupModuleSetupAbi } from '@safe-global/safe-erc4337/build/artifacts/contracts/SafeModuleSetup.sol/SafeModuleSetup.json'
import {
abi as WebAuthnSignerAbi,
bytecode as WebAuthSignerBytecode,
@@ -24,7 +24,7 @@ import {
SAFE_PROXY_FACTORY_ADDRESS,
WEBAUTHN_VERIFIER_ADDRESS,
} from '../config'
-import { UserOperation } from './userOp'
+import { PackedUserOperation } from './userOp'
// Hardcoded because we cannot easily install @safe-global/safe-contracts because of conflicting ethers.js versions
const SafeProxyBytecode =
@@ -160,14 +160,14 @@ function getSafeAddress(
}
/**
- * Encodes the function call to enable modules in the AddModulesLib contract.
+ * Encodes the function call to enable modules in the SafeModuleSetup contract.
*
* @param modules - An array of module addresses.
* @returns The encoded function call data.
*/
-function encodeAddModuleLibCall(modules: string[]): string {
- const addModulesLibInterface = new ethers.Interface(SetupModulesAbi) as unknown as SafeModuleSetup['interface']
- return addModulesLibInterface.encodeFunctionData('enableModules', [modules])
+function encodeSafeModuleSetupCall(modules: string[]): string {
+ const safeModuleSetupInterface = new ethers.Interface(SetupModuleSetupAbi) as unknown as SafeModuleSetup['interface']
+ return safeModuleSetupInterface.encodeFunctionData('enableModules', [modules])
}
/**
@@ -210,12 +210,12 @@ function getExecuteUserOpData(to: string, value: ethers.BigNumberish, data: stri
/**
* Encodes the user operation data for validating a user operation.
- * @param userOp The user operation to be validated.
+ * @param userOp The packed user operation to be validated.
* @param userOpHash The hash of the user operation.
* @param missingAccountFunds The amount of missing account funds.
* @returns The encoded data for validating the user operation.
*/
-function getValidateUserOpData(userOp: UserOperation, userOpHash: string, missingAccountFunds: ethers.BigNumberish): string {
+function getValidateUserOpData(userOp: PackedUserOperation, userOpHash: string, missingAccountFunds: ethers.BigNumberish): string {
const safe4337ModuleInterface = new ethers.Interface(Safe4337ModuleAbi) as unknown as Safe4337Module['interface']
const validateUserOpData = safe4337ModuleInterface.encodeFunctionData('validateUserOp', [userOp, userOpHash, missingAccountFunds])
@@ -238,5 +238,5 @@ export {
getValidateUserOpData,
getInitHash,
getLaunchpadInitializer,
- encodeAddModuleLibCall,
+ encodeSafeModuleSetupCall,
}
diff --git a/examples/safe-4337-passkeys/src/logic/userOp.ts b/examples/safe-4337-passkeys/src/logic/userOp.ts
index 24582039..2871cde6 100644
--- a/examples/safe-4337-passkeys/src/logic/userOp.ts
+++ b/examples/safe-4337-passkeys/src/logic/userOp.ts
@@ -20,22 +20,38 @@ import { encodeSafeMintData } from './erc721'
import { PasskeyLocalStorageFormat } from './passkeys'
import { hexStringToUint8Array } from '../utils'
+type PackedUserOperation = {
+ sender: string
+ nonce: ethers.BigNumberish
+ initCode: ethers.BytesLike
+ callData: ethers.BytesLike
+ accountGasLimits: ethers.BytesLike
+ preVerificationGas: ethers.BigNumberish
+ gasFees: ethers.BytesLike
+ paymasterAndData: ethers.BytesLike
+ signature: ethers.BytesLike
+}
+
+type UnsignedPackedUserOperation = Omit
+
type UserOperation = {
sender: string
- nonce: string
- initCode: string
- callData: string
+ nonce: ethers.BigNumberish
+ factory?: string
+ factoryData?: ethers.BytesLike
+ callData: ethers.BytesLike
callGasLimit: ethers.BigNumberish
verificationGasLimit: ethers.BigNumberish
preVerificationGas: ethers.BigNumberish
maxFeePerGas: ethers.BigNumberish
maxPriorityFeePerGas: ethers.BigNumberish
- paymasterAndData: string
- signature: string
+ paymaster?: string
+ paymasterVerificationGasLimit?: ethers.BigNumberish
+ paymasterPostOpGasLimit?: ethers.BigNumberish
+ paymasterData?: ethers.BytesLike
+ signature: ethers.BytesLike
}
-type UnsignedUserOperation = Omit
-
// Dummy signature for gas estimation. We require it so the estimation doesn't revert
// if the signature is absent
const DUMMY_SIGNATURE =
@@ -73,7 +89,7 @@ function prepareUserOperationWithInitialisation(
initializer: SafeInitializer,
afterInitializationOpCall?: UserOpCall,
saltNonce = ethers.ZeroHash,
-): UnsignedUserOperation {
+): UnsignedPackedUserOperation {
const initHash = getInitHash(initializer, APP_CHAIN_ID)
const launchpadInitializer = getLaunchpadInitializer(initHash)
const predictedSafeAddress = getSafeAddress(launchpadInitializer, SAFE_PROXY_FACTORY_ADDRESS, SAFE_SIGNER_LAUNCHPAD_ADDRESS, saltNonce)
@@ -93,11 +109,13 @@ function prepareUserOperationWithInitialisation(
initializer,
getExecuteUserOpData(userOpCall.to, userOpCall.value, userOpCall.data, userOpCall.operation),
),
- callGasLimit: ethers.toBeHex(2000000),
- verificationGasLimit: ethers.toBeHex(2000000),
+ ...packGasParameters({
+ callGasLimit: ethers.toBeHex(2000000),
+ verificationGasLimit: ethers.toBeHex(2000000),
+ maxFeePerGas: ethers.toBeHex(10000000000),
+ maxPriorityFeePerGas: ethers.toBeHex(10000000000),
+ }),
preVerificationGas: ethers.toBeHex(2000000),
- maxFeePerGas: ethers.toBeHex(10000000000),
- maxPriorityFeePerGas: ethers.toBeHex(10000000000),
paymasterAndData: '0x',
}
@@ -135,15 +153,55 @@ type UserOpGasLimitEstimation = {
* @param entryPointAddress - The entry point address. Default value is ENTRYPOINT_ADDRESS.
* @returns A promise that resolves to the estimated gas limit for the user operation.
*/
-function estimateUserOpGasLimit(userOp: UnsignedUserOperation, entryPointAddress = ENTRYPOINT_ADDRESS): Promise {
- ;(userOp as UserOperation).signature = DUMMY_SIGNATURE
-
+function estimateUserOpGasLimit(
+ userOp: UnsignedPackedUserOperation,
+ entryPointAddress = ENTRYPOINT_ADDRESS,
+): Promise {
const provider = getEip4337BundlerProvider()
- const estimation = provider.send('eth_estimateUserOperationGas', [userOp, entryPointAddress])
+ const rpcUserOp = unpackUserOperationForRpc(userOp, DUMMY_SIGNATURE)
+ const estimation = provider.send('eth_estimateUserOperationGas', [rpcUserOp, entryPointAddress])
return estimation
}
+/**
+ * Unpacks a user operation for use over the bundler RPC.
+ * @param userOp The user operation to unpack.
+ * @param signature The signature bytes for the user operation.
+ * @returns An unpacked `UserOperation` that can be used over bunlder RPC.
+ */
+function unpackUserOperationForRpc(userOp: UnsignedPackedUserOperation, signature: ethers.BytesLike): UserOperation {
+ const initFields =
+ ethers.dataLength(userOp.initCode) > 0
+ ? {
+ factory: ethers.getAddress(ethers.dataSlice(userOp.initCode, 0, 20)),
+ factoryData: ethers.dataSlice(userOp.initCode, 20),
+ }
+ : {}
+ const paymasterFields =
+ ethers.dataLength(userOp.paymasterAndData) > 0
+ ? {
+ paymaster: ethers.getAddress(ethers.dataSlice(userOp.initCode, 0, 20)),
+ paymasterVerificationGasLimit: ethers.toBeHex(ethers.dataSlice(userOp.paymasterAndData, 20, 36)),
+ paymasterPostOpGasLimit: ethers.toBeHex(ethers.dataSlice(userOp.paymasterAndData, 36, 52)),
+ paymasterData: ethers.dataSlice(userOp.paymasterAndData, 52),
+ }
+ : {}
+ return {
+ sender: ethers.getAddress(userOp.sender),
+ nonce: ethers.toBeHex(userOp.nonce),
+ ...initFields,
+ callData: ethers.hexlify(userOp.callData),
+ callGasLimit: ethers.toBeHex(ethers.dataSlice(userOp.accountGasLimits, 16, 32)),
+ verificationGasLimit: ethers.toBeHex(ethers.dataSlice(userOp.accountGasLimits, 0, 16)),
+ preVerificationGas: ethers.toBeHex(userOp.preVerificationGas),
+ maxFeePerGas: ethers.toBeHex(ethers.dataSlice(userOp.gasFees, 16, 32)),
+ maxPriorityFeePerGas: ethers.toBeHex(ethers.dataSlice(userOp.gasFees, 0, 16)),
+ ...paymasterFields,
+ signature: ethers.hexlify(signature),
+ }
+}
+
/**
* Calculates the required prefund amount based on the maximum fee per gas,
* user operation gas limit estimation, and a multiplier.
@@ -164,23 +222,35 @@ function getRequiredPrefund(maxFeePerGas: bigint, userOpGasLimitEstimation: User
)
}
+/**
+ * Pasks a user operation gas parameters.
+ * @param op The UserOperation gas parameters to pack.
+ * @returns The packed UserOperation parameters.
+ */
+function packGasParameters(
+ op: Pick,
+): Pick {
+ return {
+ accountGasLimits: ethers.solidityPacked(['uint128', 'uint128'], [op.verificationGasLimit, op.callGasLimit]),
+ gasFees: ethers.solidityPacked(['uint128', 'uint128'], [op.maxPriorityFeePerGas, op.maxFeePerGas]),
+ }
+}
+
/**
* Packs a UserOperation object into a string using the defaultAbiCoder.
* @param op The UserOperation object to pack.
* @returns The packed UserOperation as a string.
*/
-function packUserOp(op: UnsignedUserOperation): string {
+function packUserOpData(op: UnsignedPackedUserOperation): string {
return ethers.AbiCoder.defaultAbiCoder().encode(
[
'address', // sender
'uint256', // nonce
'bytes32', // initCode
'bytes32', // callData
- 'uint256', // callGasLimit
- 'uint256', // verificationGasLimit
+ 'bytes32', // accountGasLimits
'uint256', // preVerificationGas
- 'uint256', // maxFeePerGas
- 'uint256', // maxPriorityFeePerGas
+ 'bytes32', // gasFees
'bytes32', // paymasterAndData
],
[
@@ -188,11 +258,9 @@ function packUserOp(op: UnsignedUserOperation): string {
op.nonce,
ethers.keccak256(op.initCode),
ethers.keccak256(op.callData),
- op.callGasLimit,
- op.verificationGasLimit,
+ op.accountGasLimits,
op.preVerificationGas,
- op.maxFeePerGas,
- op.maxPriorityFeePerGas,
+ op.gasFees,
ethers.keccak256(op.paymasterAndData),
],
)
@@ -206,11 +274,11 @@ function packUserOp(op: UnsignedUserOperation): string {
* @returns The hash of the user operation.
*/
function getUserOpHash(
- op: UnsignedUserOperation,
+ op: UnsignedPackedUserOperation,
entryPoint: string = ENTRYPOINT_ADDRESS,
chainId: ethers.BigNumberish = APP_CHAIN_ID,
): string {
- const userOpHash = ethers.keccak256(packUserOp(op))
+ const userOpHash = ethers.keccak256(packUserOpData(op))
const enc = ethers.AbiCoder.defaultAbiCoder().encode(['bytes32', 'address', 'uint256'], [userOpHash, entryPoint, chainId])
return ethers.keccak256(enc)
}
@@ -287,7 +355,7 @@ type Assertion = {
* @throws An error if signing the user operation fails.
*/
async function signAndSendUserOp(
- userOp: UnsignedUserOperation,
+ userOp: UnsignedPackedUserOperation,
passkey: PasskeyLocalStorageFormat,
entryPoint: string = ENTRYPOINT_ADDRESS,
chainId: ethers.BigNumberish = APP_CHAIN_ID,
@@ -342,15 +410,15 @@ async function signAndSendUserOp(
],
)
- const userOpWithSignature = { ...userOp, signature }
-
- return await getEip4337BundlerProvider().send('eth_sendUserOperation', [userOpWithSignature, entryPoint])
+ const rpcUserOp = unpackUserOperationForRpc(userOp, signature)
+ return await getEip4337BundlerProvider().send('eth_sendUserOperation', [rpcUserOp, entryPoint])
}
-export type { UserOperation, UnsignedUserOperation, UserOpGasLimitEstimation }
+export type { PackedUserOperation, UnsignedPackedUserOperation, UserOperation, UserOpGasLimitEstimation }
export {
prepareUserOperationWithInitialisation,
+ packGasParameters,
getEip4337BundlerProvider,
estimateUserOpGasLimit,
getRequiredPrefund,
diff --git a/examples/safe-4337-passkeys/src/logic/wallets.ts b/examples/safe-4337-passkeys/src/logic/wallets.ts
index d8ce881b..81c9382d 100644
--- a/examples/safe-4337-passkeys/src/logic/wallets.ts
+++ b/examples/safe-4337-passkeys/src/logic/wallets.ts
@@ -4,12 +4,12 @@ import { numberToUnpaddedHex } from '../utils'
const projectId = import.meta.env.VITE_WC_CLOUD_PROJECT_ID
-const mumbai = {
- chainId: 80001,
- name: 'Polygon Mumbai',
- currency: 'MATIC',
- explorerUrl: 'https://mumbai.polygonscan.com',
- rpcUrl: 'https://rpc-mumbai.maticvigil.com',
+const sepolia = {
+ chainId: 11155111,
+ name: 'Sepolia test network',
+ currency: 'ETH',
+ explorerUrl: 'https://sepolia.etherscan.io',
+ rpcUrl: 'https://sepolia.gateway.tenderly.co',
}
const metadata = {
@@ -21,38 +21,37 @@ const metadata = {
createWeb3Modal({
ethersConfig: defaultConfig({ metadata }),
- // defaultChain: mumbai,
- chains: [mumbai],
+ chains: [sepolia],
projectId,
})
/**
- * Switches the Ethereum provider to the Mumbai network.
+ * Switches the Ethereum provider to the Ethereum Sepolia test network.
* @param provider The Ethereum provider.
* @returns A promise that resolves to an unknown value.
*/
-async function switchToMumbai(provider: ethers.Eip1193Provider): Promise {
+async function switchToSepolia(provider: ethers.Eip1193Provider): Promise {
return provider
.request({
method: 'wallet_addEthereumChain',
params: [
{
- chainId: numberToUnpaddedHex(mumbai.chainId),
- blockExplorerUrls: [mumbai.explorerUrl],
- chainName: mumbai.name,
+ chainId: numberToUnpaddedHex(sepolia.chainId),
+ blockExplorerUrls: [sepolia.explorerUrl],
+ chainName: sepolia.name,
nativeCurrency: {
- name: mumbai.currency,
- symbol: mumbai.currency,
+ name: sepolia.currency,
+ symbol: sepolia.currency,
decimals: 18,
},
- rpcUrls: [mumbai.rpcUrl],
+ rpcUrls: [sepolia.rpcUrl],
},
],
})
.catch(() =>
provider.request({
method: 'wallet_switchEthereumChain',
- params: [{ chainId: numberToUnpaddedHex(mumbai.chainId) }],
+ params: [{ chainId: numberToUnpaddedHex(sepolia.chainId) }],
}),
)
}
@@ -66,4 +65,4 @@ function getJsonRpcProviderFromEip1193Provider(provider: ethers.Eip1193Provider)
return new ethers.BrowserProvider(provider)
}
-export { switchToMumbai, getJsonRpcProviderFromEip1193Provider }
+export { switchToSepolia, getJsonRpcProviderFromEip1193Provider }
diff --git a/modules/4337/hardhat.config.ts b/modules/4337/hardhat.config.ts
index 627dbb60..ea289c14 100644
--- a/modules/4337/hardhat.config.ts
+++ b/modules/4337/hardhat.config.ts
@@ -25,7 +25,7 @@ if (PK) {
}
}
-if (['mainnet', 'goerli', 'mumbai', 'polygon'].includes(argv.network) && INFURA_KEY === undefined) {
+if (['mainnet', 'sepolia', 'polygon', 'amoy'].includes(argv.network) && INFURA_KEY === undefined) {
throw new Error(`Could not find Infura key in env, unable to connect to network ${argv.network}`)
}
@@ -87,19 +87,14 @@ const userConfig: HardhatUserConfig = {
...sharedNetworkConfig,
url: `https://polygon-mainnet.infura.io/v3/${INFURA_KEY}`,
},
- goerli: {
- ...sharedNetworkConfig,
- url: `https://goerli.infura.io/v3/${INFURA_KEY}`,
- tags: ['dev'],
- },
sepolia: {
...sharedNetworkConfig,
url: `https://sepolia.infura.io/v3/${INFURA_KEY}`,
tags: ['dev'],
},
- mumbai: {
+ amoy: {
...sharedNetworkConfig,
- url: `https://polygon-mumbai.infura.io/v3/${INFURA_KEY}`,
+ url: `https://polygon-amoy.infura.io/v3/${INFURA_KEY}`,
tags: ['dev'],
},
...customNetwork,
diff --git a/modules/4337/src/deploy/launchpad.ts b/modules/4337/src/deploy/launchpad.ts
index ace7d404..70071f67 100644
--- a/modules/4337/src/deploy/launchpad.ts
+++ b/modules/4337/src/deploy/launchpad.ts
@@ -18,4 +18,6 @@ const deploy: DeployFunction = async ({ deployments, getNamedAccounts, network }
})
}
+deploy.dependencies = ['entrypoint']
+
export default deploy