Skip to content

Commit

Permalink
Fix 0.7 Compilation Issues In Passkey Example (#303)
Browse files Browse the repository at this point in the history
Partially addresses #270 

This PR modifies the passkey example to compile once again for the 0.7
EntryPoint changes. Note that the contract addresses are also updated,
as well as the network the example is for. This is because Polygon
Mumbai is not well supported seeing as it is anchored to Goerli which is
deprecated.

Test transaction using the example application:
https://sepolia.etherscan.io/tx/0x267fa1cd04ba44701807c10ea6f7885c45c22c3ff6646fb9ef697884d91fedc8
  • Loading branch information
nlordell committed Mar 5, 2024
1 parent d5a91f4 commit 83cb644
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
12 changes: 6 additions & 6 deletions examples/safe-4337-passkeys/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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')
}
}
}
Expand Down Expand Up @@ -72,8 +72,8 @@ function App() {
if (connectedToWrongChain) {
content = (
<div className="card">
<p>Please switch to Mumbai network to continue</p>
<button onClick={handleSwitchToMumbaiClick}>Switch to Mumbai</button>
<p>Please switch to Ethereum Sepolia test network to continue</p>
<button onClick={handleSwitchToSepoliaClick}>Switch to Sepolia</button>
</div>
)
}
Expand Down
32 changes: 20 additions & 12 deletions examples/safe-4337-passkeys/src/components/SafeCard.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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],
)
Expand Down Expand Up @@ -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)
Expand All @@ -84,14 +92,14 @@ function SafeCard({ passkey, provider }: { passkey: PasskeyLocalStorageFormat; p
{userOpHash && (
<p>
Your Safe is being deployed. Track the user operation on{' '}
<a href={`https://jiffyscan.xyz/userOpHash/${userOpHash}?network=mumbai`}>jiffyscan</a>
<a href={`https://jiffyscan.xyz/userOpHash/${userOpHash}?network=sepolia`}>jiffyscan</a>
</p>
)}

{deployed && (
<p>
Your Safe has been deployed. More info on{' '}
<a href={`https://jiffyscan.xyz/account/${unsignedUserOperation.sender}?network=mumbai`}>jiffyscan</a>
<a href={`https://jiffyscan.xyz/account/${unsignedUserOperation.sender}?network=sepolia`}>jiffyscan</a>
</p>
)}

Expand Down
16 changes: 8 additions & 8 deletions examples/safe-4337-passkeys/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
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'

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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useState, useEffect } from 'react'
import { UnsignedUserOperation, UserOpGasLimitEstimation, estimateUserOpGasLimit } from '../logic/userOp'
import { UnsignedPackedUserOperation, UserOpGasLimitEstimation, estimateUserOpGasLimit } from '../logic/userOp'
import { RequestStatus } from '../utils'

/**
* Custom hook for estimating the gas limit of a user operation.
* @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<UserOpGasLimitEstimation | undefined>(undefined)
const [status, setStatus] = useState<RequestStatus>(RequestStatus.NOT_REQUESTED)

Expand Down
18 changes: 9 additions & 9 deletions examples/safe-4337-passkeys/src/logic/safe.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 =
Expand Down Expand Up @@ -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])
}

/**
Expand Down Expand Up @@ -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])
Expand All @@ -238,5 +238,5 @@ export {
getValidateUserOpData,
getInitHash,
getLaunchpadInitializer,
encodeAddModuleLibCall,
encodeSafeModuleSetupCall,
}
Loading

0 comments on commit 83cb644

Please sign in to comment.