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