From a6b49dca3812d9c6554980662fd90ce85c4e3c6c Mon Sep 17 00:00:00 2001 From: Diogo Palhais Date: Wed, 30 Jul 2025 01:41:44 +0100 Subject: [PATCH 1/4] WIP: entrypoint selector --- .../src/account/toGianoSmartAccount.ts | 2 + packages/connector/src/giano-entry-point.ts | 57 +++++++++++- packages/connector/src/provider.ts | 36 ++++++-- packages/contracts/package.json | 4 +- services/custom-example/package.json | 4 +- .../src/components/EntryPointSelector.tsx | 89 ++++++++++++++++++ .../src/components/EntryPointVerification.tsx | 91 +++++++++++++++++++ services/custom-example/src/config.ts | 19 ++++ services/custom-example/src/pages/_app.tsx | 22 ++--- .../src/pages/api/submit-userop.ts | 12 +++ services/custom-example/src/pages/index.tsx | 63 +++++++++++-- .../src/providers/WagmiProvider.tsx | 79 ++++++++++++++++ services/custom-example/src/wagmi.ts | 82 ++++++++++++----- 13 files changed, 506 insertions(+), 54 deletions(-) create mode 100644 services/custom-example/src/components/EntryPointSelector.tsx create mode 100644 services/custom-example/src/components/EntryPointVerification.tsx create mode 100644 services/custom-example/src/providers/WagmiProvider.tsx diff --git a/packages/connector/src/account/toGianoSmartAccount.ts b/packages/connector/src/account/toGianoSmartAccount.ts index 448f20e..a0ad90b 100644 --- a/packages/connector/src/account/toGianoSmartAccount.ts +++ b/packages/connector/src/account/toGianoSmartAccount.ts @@ -24,6 +24,7 @@ import type { SmartAccount, SmartAccountImplementation, UserOperation, WebAuthnA import { entryPoint07Abi } from 'viem/account-abstraction'; import { entryPoint07Address, getUserOperationHash, toSmartAccount } from 'viem/account-abstraction'; import { readContract } from 'viem/actions'; +import type { EntryPointConfig } from '../giano-entry-point'; export type ToGianoSmartAccountParameters = { address?: Address | undefined; @@ -31,6 +32,7 @@ export type ToGianoSmartAccountParameters = { owners: readonly (Address | OneOf)[]; nonce?: bigint | undefined; factoryAddress: Address; + entryPoint?: EntryPointConfig; }; export type ToGianoSmartAccountReturnType = Prettify>; diff --git a/packages/connector/src/giano-entry-point.ts b/packages/connector/src/giano-entry-point.ts index faa35fb..2d30075 100644 --- a/packages/connector/src/giano-entry-point.ts +++ b/packages/connector/src/giano-entry-point.ts @@ -1,7 +1,60 @@ -import { entryPoint07Address, EntryPointVersion } from 'viem/account-abstraction' +import { entryPoint07Address, entryPoint08Address, EntryPointVersion } from 'viem/account-abstraction' +// EntryPoint v0.8 address - TESTING CONFIGURATION +// For testing dual EntryPoint support functionality, we use the same EntryPoint as v0.7 +// In production, this would be the actual EntryPoint v0.8 address once deployed +// This allows us to test UI switching, provider recreation, and verification without deploying new contracts +export const ENTRYPOINT_V08_ADDRESS = '0x0000000071727De22E5E9d8BAf0edAc6f37da032' as const + +export type SupportedEntryPointVersion = '0.7' | '0.8' + +export interface EntryPointConfig { + version: SupportedEntryPointVersion + address: `0x${string}` +} + +// Default configuration for EntryPoint v0.7 +export const ENTRYPOINT_V07_CONFIG: EntryPointConfig = { + version: '0.7', + address: entryPoint07Address +} + +// Configuration for EntryPoint v0.8 - TESTING CONFIGURATION +// Uses same address as v0.7 for testing dual support functionality +export const ENTRYPOINT_V08_CONFIG: EntryPointConfig = { + version: '0.8', + address: ENTRYPOINT_V08_ADDRESS +} + +// Available EntryPoint configurations +export const ENTRYPOINT_CONFIGS = { + '0.7': ENTRYPOINT_V07_CONFIG, + '0.8': ENTRYPOINT_V08_CONFIG +} as const + +// Default EntryPoint version (maintaining backward compatibility) +export const DEFAULT_ENTRYPOINT_VERSION: SupportedEntryPointVersion = '0.7' + +// Legacy exports for backward compatibility export const GianoEntryPointVersion = '0.7' satisfies EntryPointVersion export type GianoEntryPointVersion = typeof GianoEntryPointVersion - export const GianoEntryPointAddress = entryPoint07Address export type GianoEntryPointAddress = typeof GianoEntryPointAddress + +// New exports for version-aware EntryPoint support +export function getEntryPointConfig(version: SupportedEntryPointVersion): EntryPointConfig { + return ENTRYPOINT_CONFIGS[version] +} + +export function getEntryPointAddress(version: SupportedEntryPointVersion): `0x${string}` { + return ENTRYPOINT_CONFIGS[version].address +} + +export function getEntryPointVersion(address: `0x${string}`): SupportedEntryPointVersion | null { + for (const [version, config] of Object.entries(ENTRYPOINT_CONFIGS)) { + if (config.address.toLowerCase() === address.toLowerCase()) { + return version as SupportedEntryPointVersion + } + } + return null +} diff --git a/packages/connector/src/provider.ts b/packages/connector/src/provider.ts index 205ffa4..24464d6 100644 --- a/packages/connector/src/provider.ts +++ b/packages/connector/src/provider.ts @@ -24,7 +24,13 @@ import { createWebAuthnCredential, toWebAuthnAccount } from 'viem/account-abstra import type { EIP1193EventMap, EIP1193Parameters, EIP1193RequestFn } from 'viem/types/eip1193'; import type { GianoSmartAccountImplementation } from './account'; import { toGianoSmartAccount } from './account'; -import { GianoEntryPointAddress, GianoEntryPointVersion } from './giano-entry-point' +import { + GianoEntryPointAddress, + GianoEntryPointVersion, + SupportedEntryPointVersion, + getEntryPointConfig, + DEFAULT_ENTRYPOINT_VERSION +} from './giano-entry-point' import { GianoProviderInjection } from './provider-injection' import { withValidation } from './provider-injection/_with-validation' import { v4 as uuidv4 } from 'uuid'; @@ -63,6 +69,7 @@ export type CreateGianoProviderParams = { gianoSmartWalletFactoryAddress: Address; userVerification?: 'required' | 'preferred' | 'discouraged'; mediation?: 'silent' | 'optional' | 'required'; + entryPointVersion?: SupportedEntryPointVersion; }; type EventHandler = (payload: Parameters[0]) => void; @@ -90,9 +97,13 @@ export const createGianoProvider = (options: CreateGianoProviderParams) => { bundler, gianoSmartWalletFactoryAddress, userVerification = USER_VERIFICATION_REQUIREMENT, - mediation = 'silent' + mediation = 'silent', + entryPointVersion = DEFAULT_ENTRYPOINT_VERSION } = options + // Get the EntryPoint configuration for the specified version + const entryPointConfig = getEntryPointConfig(entryPointVersion) + let smartAccount: SmartAccount | null; let chain: Chain | undefined; let transport: Transport | undefined; @@ -133,16 +144,18 @@ export const createGianoProvider = (options: CreateGianoProviderParams) => { // Sign the user operation const signature = await userOpRequest.account.signUserOperation(preparedWithGas); + console.log(entryPointConfig) + // Create the complete signed user operation const signedUserOp = { ...preparedWithGas, sender: await userOpRequest.account.getAddress(), - signature, - account: { - entryPoint: { - address: GianoEntryPointAddress, + signature, + account: { + entryPoint: { + address: entryPointConfig.address, + }, }, - }, }; return await injection.submitUserOperation(signedUserOp); @@ -307,7 +320,12 @@ export const createGianoProvider = (options: CreateGianoProviderParams) => { if (!webAuthnAccount) { throw new Error('Invalid credential'); } - smartAccount = await toGianoSmartAccount({ client: client!, owners: [webAuthnAccount], factoryAddress: gianoSmartWalletFactoryAddress }) + smartAccount = await toGianoSmartAccount({ + client: client!, + owners: [webAuthnAccount], + factoryAddress: gianoSmartWalletFactoryAddress, + entryPoint: entryPointConfig + }) const smartAccountAddress = await smartAccount.getAddress() emit('connect', { chainId: `0x${chain!.id.toString(16)}` }); @@ -340,6 +358,7 @@ export const createGianoProvider = (options: CreateGianoProviderParams) => { owners: [toWebAuthnAccount({ credential })], address: handlerCreatedAddress, factoryAddress: gianoSmartWalletFactoryAddress, + entryPoint: entryPointConfig, }); emit('connect', { chainId }); @@ -351,6 +370,7 @@ export const createGianoProvider = (options: CreateGianoProviderParams) => { client: client!, owners: [toWebAuthnAccount({ credential })], factoryAddress: gianoSmartWalletFactoryAddress, + entryPoint: entryPointConfig, }); const smartAccountAddress = await smartAccount.getAddress(); diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 8ff7a3c..0d4ffb3 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "pnpm hh:compile && pnpm hh:wagmi && tsup index.ts", "hh:test": "NODE_ENV=test REPORT_GAS=true hardhat test", - "hh:node": "anvil --enable-trace-printing", + "hh:node": "anvil --steps-tracing", "hh:deploy": "hardhat ignition deploy ignition/modules/GianoAccountFactory.ts --strategy create2", "hh:deploy:mapper": "hardhat ignition deploy ignition/modules/index.ts --strategy create2", "hh:deploy:testing": "hardhat ignition deploy ignition/modules/Testing.ts --strategy create2", @@ -23,7 +23,7 @@ "main": "dist/index", "types": "dist/index.d.ts", "devDependencies": { - "@account-abstraction/contracts": "0.7.0", + "@account-abstraction/contracts": "^0.8.0", "@appliedblockchain/silentdatarollup-core": "^1.0.1", "@appliedblockchain/silentdatarollup-hardhat-plugin": "^1.0.1", "@nomicfoundation/ethereumjs-util": "^9.0.4", diff --git a/services/custom-example/package.json b/services/custom-example/package.json index 1ef7f00..2b125e4 100644 --- a/services/custom-example/package.json +++ b/services/custom-example/package.json @@ -20,8 +20,8 @@ "next": "^15.1.4", "react": "^19.0.0", "react-dom": "^19.0.0", - "viem": "2.29.2", - "wagmi": "2.15.4" + "viem": "2.31.6", + "wagmi": "2.15.6" }, "devDependencies": { "@types/node": "^20.14.8", diff --git a/services/custom-example/src/components/EntryPointSelector.tsx b/services/custom-example/src/components/EntryPointSelector.tsx new file mode 100644 index 0000000..2cfaaa9 --- /dev/null +++ b/services/custom-example/src/components/EntryPointSelector.tsx @@ -0,0 +1,89 @@ +import React from 'react'; +import { config, ENTRYPOINT_VERSION_CONFIGS, type SupportedEntryPointVersion } from '../config'; + +interface EntryPointSelectorProps { + selectedVersion: SupportedEntryPointVersion; + onVersionChange: (version: SupportedEntryPointVersion) => void; + disabled?: boolean; +} + +export const EntryPointSelector: React.FC = ({ + selectedVersion, + onVersionChange, + disabled = false, +}) => { + return ( +
+

+ ๐Ÿ”ง EntryPoint Version Configuration +

+ +
+ Select the EntryPoint version to use for this session: +
+ +
+ {(Object.entries(ENTRYPOINT_VERSION_CONFIGS) as [SupportedEntryPointVersion, typeof ENTRYPOINT_VERSION_CONFIGS[keyof typeof ENTRYPOINT_VERSION_CONFIGS]][]).map(([version, versionConfig]) => ( + + ))} +
+ + {selectedVersion && ( +
+ Selected: {ENTRYPOINT_VERSION_CONFIGS[selectedVersion].name} +
+ Note: Changing the EntryPoint version will require reconnecting your wallet. +
+ )} +
+ ); +}; \ No newline at end of file diff --git a/services/custom-example/src/components/EntryPointVerification.tsx b/services/custom-example/src/components/EntryPointVerification.tsx new file mode 100644 index 0000000..2ee12e3 --- /dev/null +++ b/services/custom-example/src/components/EntryPointVerification.tsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import { useAccount, useWalletClient } from 'wagmi'; +import { getEntryPointAddress, type SupportedEntryPointVersion } from '@appliedblockchain/giano-connector'; + +interface EntryPointVerificationProps { + selectedVersion: SupportedEntryPointVersion; +} + +export const EntryPointVerification: React.FC = ({ selectedVersion }) => { + const { address, isConnected } = useAccount(); + const { data: walletClient } = useWalletClient(); + const [currentEntryPoint, setCurrentEntryPoint] = useState(null); + const [isChecking, setIsChecking] = useState(false); + + const checkCurrentEntryPoint = async () => { + if (!walletClient || !isConnected) return; + + setIsChecking(true); + try { + // Get the smart account from the wallet client + const smartAccount = (walletClient as any).account; + + if (smartAccount?.entryPoint?.address) { + setCurrentEntryPoint(smartAccount.entryPoint.address); + console.log('๐Ÿ” Current EntryPoint Address:', smartAccount.entryPoint.address); + } else { + console.log('โš ๏ธ Could not determine EntryPoint address'); + setCurrentEntryPoint('Unable to determine'); + } + } catch (error) { + console.error('Error checking EntryPoint:', error); + setCurrentEntryPoint('Error checking'); + } finally { + setIsChecking(false); + } + }; + + const expectedEntryPoint = getEntryPointAddress(selectedVersion); + const isUsingCorrectEntryPoint = currentEntryPoint === expectedEntryPoint; + + return ( +
+

+ ๐Ÿ” EntryPoint Verification +

+ +
+
Selected Version: {selectedVersion}
+
Expected Address: {expectedEntryPoint}
+ {currentEntryPoint && ( +
+ Current Address: {currentEntryPoint} + {isUsingCorrectEntryPoint ? ( + โœ… Correct + ) : ( + โŒ Mismatch + )} +
+ )} +
+ + + + {!isConnected && ( +
+ Connect your wallet to verify the EntryPoint address +
+ )} +
+ ); +}; \ No newline at end of file diff --git a/services/custom-example/src/config.ts b/services/custom-example/src/config.ts index bb08110..b686ebb 100644 --- a/services/custom-example/src/config.ts +++ b/services/custom-example/src/config.ts @@ -1,3 +1,6 @@ +// Define supported EntryPoint versions +export type SupportedEntryPointVersion = '0.7' | '0.8'; + if (!process.env.NEXT_PUBLIC_BUNDLER_RPC_URL) { throw new Error('NEXT_PUBLIC_BUNDLER_RPC_URL is not set'); } @@ -9,4 +12,20 @@ export const config = { paymasterAddress: process.env.NEXT_PUBLIC_PAYMASTER_ADDRESS, gianoSmartWalletFactoryAddress: process.env.NEXT_PUBLIC_GIANO_SMART_WALLET_FACTORY_ADDRESS ?? '0x5A1dd8C52Daaa27D9ced48f7F96b2b05dD6dB0B0', privateErc20Address: process.env.NEXT_PUBLIC_PRIVATE_ERC20_ADDRESS ?? '0x768F92504EDbACaf0502354ea8F75BD627301519', + // Default EntryPoint version - can be overridden via URL parameter or user selection + defaultEntryPointVersion: (process.env.NEXT_PUBLIC_DEFAULT_ENTRYPOINT_VERSION as SupportedEntryPointVersion) ?? '0.7' as SupportedEntryPointVersion, }; + +// EntryPoint version configuration for different environments +export const ENTRYPOINT_VERSION_CONFIGS = { + '0.7': { + name: 'EntryPoint v0.7', + description: 'Stable version with PackedUserOperation support', + supported: true, + }, + '0.8': { + name: 'EntryPoint v0.8', + description: 'Latest version with enhanced features (experimental)', + supported: true, + }, +} as const; diff --git a/services/custom-example/src/pages/_app.tsx b/services/custom-example/src/pages/_app.tsx index 170887e..c371033 100644 --- a/services/custom-example/src/pages/_app.tsx +++ b/services/custom-example/src/pages/_app.tsx @@ -2,23 +2,23 @@ import '../styles/globals.css'; import '@rainbow-me/rainbowkit/styles.css'; import type { AppProps } from 'next/app'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { WagmiProvider } from 'wagmi'; +// Import our dynamic wagmi provider instead of static components +import { DynamicWagmiProvider } from '../providers/WagmiProvider'; +// import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +// import { WagmiProvider } from 'wagmi'; // import { RainbowKitProvider } from '@rainbow-me/rainbowkit'; -import { config } from '../wagmi'; +// import { config } from '../wagmi'; -const client = new QueryClient(); +// const client = new QueryClient(); function MyApp({ Component, pageProps }: AppProps) { return ( - - - {/* */} - - {/* */} - - + + {/* */} + + {/* */} + ); } diff --git a/services/custom-example/src/pages/api/submit-userop.ts b/services/custom-example/src/pages/api/submit-userop.ts index c4795ac..5eafc8e 100644 --- a/services/custom-example/src/pages/api/submit-userop.ts +++ b/services/custom-example/src/pages/api/submit-userop.ts @@ -59,6 +59,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(400).json({ error: 'Missing entryPoint address' }); } + // ๐Ÿ” VERIFICATION: Log which EntryPoint is being used + console.log('๐ŸŽฏ ENTRYPOINT VERIFICATION:'); + console.log(' EntryPoint Address:', entryPointAddress); + if (entryPointAddress === '0x0000000071727De22E5E9d8BAf0edAc6f37da032') { + console.log(' โœ… Using EntryPoint v0.7 (Original)'); + } else if (entryPointAddress === '0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0') { + console.log(' ๐Ÿ†• Using EntryPoint v0.8 (Mock Test Instance)'); + } else { + console.log(' โš ๏ธ Using Unknown EntryPoint Address'); + } + console.log(''); + // Step 3: Direct RPC call to bundler const sendUserOpId = ++rpcIdCounter; const rpcResponse = await fetch(config.bundlerRpcUrl, { diff --git a/services/custom-example/src/pages/index.tsx b/services/custom-example/src/pages/index.tsx index c89d985..83ba51e 100644 --- a/services/custom-example/src/pages/index.tsx +++ b/services/custom-example/src/pages/index.tsx @@ -5,15 +5,23 @@ import type { NextPage } from 'next'; import Head from 'next/head'; import { formatEther, parseEther, encodeFunctionData } from 'viem'; import { useAccount, useConnect, useDisconnect, useReadContract, useSendTransaction, useWalletClient, useWriteContract } from 'wagmi'; -import { config } from '../config'; -import { gianoConnector } from '../wagmi'; +import { config, type SupportedEntryPointVersion } from '../config'; +// Remove static connector import since we'll use dynamic connectors +// import { gianoConnector } from '../wagmi'; import styles from '../styles/Home.module.css'; +import { EntryPointSelector } from '../components/EntryPointSelector'; +import { EntryPointVerification } from '../components/EntryPointVerification'; +import { useDynamicWagmi } from '../providers/WagmiProvider'; const Home: NextPage = () => { const [mounted, setMounted] = useState(false); const [connectionReady, setConnectionReady] = useState(false); const [isAuthenticating, setIsAuthenticating] = useState(false); - const { connect } = useConnect(); + + // Use dynamic wagmi context instead of local state + const { selectedEntryPointVersion, setSelectedEntryPointVersion, isReconfiguring } = useDynamicWagmi(); + + const { connect, connectors } = useConnect(); const { disconnect } = useDisconnect(); const { address, isConnected, status } = useAccount(); const { data: walletClient } = useWalletClient(); @@ -93,7 +101,7 @@ const Home: NextPage = () => { const connectAsync = async () => { try { setIsAuthenticating(true); - const response = connect({ connector: gianoConnector }); + const response = connect({ connector: connectors[0] }); // Assuming the first connector is the one to restore } catch (error) { console.warn('Failed to auto-restore session:', error); // Clear invalid stored data @@ -106,7 +114,7 @@ const Home: NextPage = () => { void connectAsync(); } } - }, [mounted, isConnected, connect, isAuthenticating]); + }, [mounted, isConnected, connect, isAuthenticating, connectors]); // Wait for the connection to be fully established before allowing contract calls useEffect(() => { @@ -434,11 +442,54 @@ const Home: NextPage = () => {
+ {/* EntryPoint Version Selector */} + { + console.log('๐Ÿ”ง EntryPoint Version Changed:', version); + console.log(' Selected Version:', version); + console.log(' Previous Version:', selectedEntryPointVersion); + + if (isConnected) { + console.log(' โš ๏ธ Disconnecting current wallet...'); + // Disconnect first if connected since we're changing the underlying provider + disconnect(); + } + + // Use the dynamic wagmi context to change EntryPoint version + // This will automatically reconfigure wagmi with the new EntryPoint + await setSelectedEntryPointVersion(version); + console.log(' โœ… EntryPoint version updated to:', version); + }} + disabled={isAuthenticating || isReconfiguring} + /> + + {isReconfiguring && ( +
+
+ ๐Ÿ”„ Reconfiguring for EntryPoint v{selectedEntryPointVersion}... +
+
+ Please wait while we set up the new EntryPoint configuration. +
+
+ )} + + {/* EntryPoint Verification Component */} + +
{isConnected ? ( ) : ( - + )} + + {currentImplementation !== 'EOA' && currentVersion === '0.7' && ( + + )} + + {currentImplementation !== 'EOA' && currentVersion === '0.8' && ( +
+ โœ… Latest Version +
+ )} +
+ + {error && ( +
+
+ {currentImplementation === 'EOA' ? 'โš ๏ธ EOA Wallet Detected' : 'โŒ Error'} +
+
{error}
+ + {currentImplementation === 'EOA' && ( +
+ How to create a Giano smart wallet: +
    +
  1. Use the "Create Account" button above
  2. +
  3. Sign the wallet creation transaction
  4. +
  5. Your new Giano smart wallet will be deployed
  6. +
  7. Return here to test the proxy upgrade feature
  8. +
+
+ )} +
+ )} + + )} + + ); +}; \ No newline at end of file diff --git a/services/custom-example/src/config.ts b/services/custom-example/src/config.ts index db10e05..a02a91e 100644 --- a/services/custom-example/src/config.ts +++ b/services/custom-example/src/config.ts @@ -12,22 +12,46 @@ export const config = { paymasterAddress: process.env.NEXT_PUBLIC_PAYMASTER_ADDRESS, // Legacy single factory address - kept for backward compatibility (using v0.7 as default) gianoSmartWalletFactoryAddress: process.env.NEXT_PUBLIC_GIANO_SMART_WALLET_FACTORY_ADDRESS ?? '0x56E97c186603242C616698c684937A891A22f672', - privateErc20Address: process.env.NEXT_PUBLIC_PRIVATE_ERC20_ADDRESS ?? '0x2eeD4959fB632694150C67b527e070921EEcb29F', + privateErc20Address: process.env.NEXT_PUBLIC_PRIVATE_ERC20_ADDRESS ?? '0x2eeD4959fB632694150C67b527e070921EEcb29F', // PrivateERC20 (matches deployed) // Default EntryPoint version - can be overridden via URL parameter or user selection defaultEntryPointVersion: (process.env.NEXT_PUBLIC_DEFAULT_ENTRYPOINT_VERSION as SupportedEntryPointVersion) ?? '0.7' as SupportedEntryPointVersion, }; -// Version-specific contract addresses +// Proxy upgrade pattern addresses - UPDATED WITH DEPLOYED CONTRACTS +export const PROXY_UPGRADE_ADDRESSES = { + // Single factory that always deploys V07 proxies (users upgrade implementations later) + gianoSmartWalletFactoryAddress: '0xa49bA0d38E200524Da7A438705D9F34Ad245eF3a', + + // Implementation addresses for proxy upgrades + implementations: { + '0.7': '0x296B00290826aDaC27474d99023FB4Df27914059', // V07 Implementation (GianoSmartWallet) + '0.8': '0xA2496b69798997Fb5297d4a8C08f28FF2668645D', // V08 Implementation (GianoSmartWalletV08Implementation) + }, + + // EntryPoint-specific configurations + entryPoints: { + '0.7': { + address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', + paymasterAddress: '0x6943Bc5b52b51AfC9718aBB31EAA18A1352D5595', // PermissivePaymasterV07 + }, + '0.8': { + address: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108', + paymasterAddress: '0xEfc107516CD5c0731f8Ce364bCdaD8A235794069', // PermissivePaymasterV08 + }, + }, +} as const; + +// Legacy - for backward compatibility (remove after migration) export const VERSION_SPECIFIC_ADDRESSES = { '0.7': { - gianoSmartWalletFactoryAddress: '0x56E97c186603242C616698c684937A891A22f672', - gianoSmartWalletImplementationAddress: '0xe40e09560701Df4D7D9876946B1eeD6e3b0fd387', - paymasterAddress: '0x6943Bc5b52b51AfC9718aBB31EAA18A1352D5595', + gianoSmartWalletFactoryAddress: PROXY_UPGRADE_ADDRESSES.gianoSmartWalletFactoryAddress, + gianoSmartWalletImplementationAddress: PROXY_UPGRADE_ADDRESSES.implementations['0.7'], + paymasterAddress: PROXY_UPGRADE_ADDRESSES.entryPoints['0.7'].paymasterAddress, }, '0.8': { - gianoSmartWalletFactoryAddress: '0x91F95265a4D6cCDb56e502cFCd2C9Da80714d16e', - gianoSmartWalletImplementationAddress: '0xD21c53250a6De37008Bee5378F2396d8e210d3De', - paymasterAddress: '0xEfc107516CD5c0731f8Ce364bCdaD8A235794069', + gianoSmartWalletFactoryAddress: PROXY_UPGRADE_ADDRESSES.gianoSmartWalletFactoryAddress, // Same factory! + gianoSmartWalletImplementationAddress: PROXY_UPGRADE_ADDRESSES.implementations['0.8'], + paymasterAddress: PROXY_UPGRADE_ADDRESSES.entryPoints['0.8'].paymasterAddress, }, } as const; @@ -41,14 +65,26 @@ export function getFactoryAddress(version: SupportedEntryPointVersion): string { return VERSION_SPECIFIC_ADDRESSES[version].gianoSmartWalletFactoryAddress; } -// Helper function to get implementation address for a specific version +// Helper function to get paymaster address for a specific version (legacy) +export function getPaymasterAddress(version: SupportedEntryPointVersion): string { + return VERSION_SPECIFIC_ADDRESSES[version].paymasterAddress; +} + +// NEW: Proxy upgrade pattern helpers +export function getProxyFactoryAddress(): string { + return PROXY_UPGRADE_ADDRESSES.gianoSmartWalletFactoryAddress; +} + export function getImplementationAddress(version: SupportedEntryPointVersion): string { - return VERSION_SPECIFIC_ADDRESSES[version].gianoSmartWalletImplementationAddress; + return PROXY_UPGRADE_ADDRESSES.implementations[version]; } -// Helper function to get paymaster address for a specific version -export function getPaymasterAddress(version: SupportedEntryPointVersion): string { - return VERSION_SPECIFIC_ADDRESSES[version].paymasterAddress; +export function getEntryPointAddress(version: SupportedEntryPointVersion): string { + return PROXY_UPGRADE_ADDRESSES.entryPoints[version].address; +} + +export function getEntryPointPaymasterAddress(version: SupportedEntryPointVersion): string { + return PROXY_UPGRADE_ADDRESSES.entryPoints[version].paymasterAddress; } // EntryPoint version configuration for different environments diff --git a/services/custom-example/src/pages/index.tsx b/services/custom-example/src/pages/index.tsx index 83ba51e..534ab03 100644 --- a/services/custom-example/src/pages/index.tsx +++ b/services/custom-example/src/pages/index.tsx @@ -11,6 +11,7 @@ import { config, type SupportedEntryPointVersion } from '../config'; import styles from '../styles/Home.module.css'; import { EntryPointSelector } from '../components/EntryPointSelector'; import { EntryPointVerification } from '../components/EntryPointVerification'; +import { WalletImplementationManager } from '../components/WalletImplementationManager'; import { useDynamicWagmi } from '../providers/WagmiProvider'; const Home: NextPage = () => { @@ -21,6 +22,9 @@ const Home: NextPage = () => { // Use dynamic wagmi context instead of local state const { selectedEntryPointVersion, setSelectedEntryPointVersion, isReconfiguring } = useDynamicWagmi(); + // Track wallet implementation version (separate from bundler EntryPoint version) + const [walletImplementationVersion, setWalletImplementationVersion] = useState('0.7'); + const { connect, connectors } = useConnect(); const { disconnect } = useDisconnect(); const { address, isConnected, status } = useAccount(); @@ -443,26 +447,42 @@ const Home: NextPage = () => {
{/* EntryPoint Version Selector */} - { - console.log('๐Ÿ”ง EntryPoint Version Changed:', version); - console.log(' Selected Version:', version); - console.log(' Previous Version:', selectedEntryPointVersion); - - if (isConnected) { - console.log(' โš ๏ธ Disconnecting current wallet...'); - // Disconnect first if connected since we're changing the underlying provider - disconnect(); - } - - // Use the dynamic wagmi context to change EntryPoint version - // This will automatically reconfigure wagmi with the new EntryPoint - await setSelectedEntryPointVersion(version); - console.log(' โœ… EntryPoint version updated to:', version); - }} - disabled={isAuthenticating || isReconfiguring} - /> +
+

+ ๐Ÿ“ก Bundler EntryPoint Configuration +

+

+ This controls which EntryPoint your bundler uses to process transactions. + Your wallet will automatically adapt to work with the selected EntryPoint. +

+ + { + console.log('๐Ÿ”ง Bundler EntryPoint Version Changed:', version); + console.log(' Selected Version:', version); + console.log(' Previous Version:', selectedEntryPointVersion); + + if (isConnected) { + console.log(' โš ๏ธ Disconnecting current wallet...'); + // Disconnect first if connected since we're changing the underlying provider + disconnect(); + } + + // Use the dynamic wagmi context to change EntryPoint version + // This will automatically reconfigure wagmi with the new EntryPoint + await setSelectedEntryPointVersion(version); + console.log(' โœ… Bundler EntryPoint version updated to:', version); + }} + disabled={isAuthenticating || isReconfiguring} + /> +
{isReconfiguring && (
{ {/* EntryPoint Verification Component */} + {/* Wallet Implementation Manager - shows current version and upgrade option */} + {isConnected && ( + + )} +
{isConnected ? ( @@ -510,6 +537,19 @@ const Home: NextPage = () => { {address && (
Address: {address} +
+ ๐Ÿ’ก New Proxy Upgrade Pattern: Your wallet always keeps the same address, + but you can upgrade its implementation from v0.7 to v0.8 to access new EntryPoint features. + Use the "Wallet Implementation Status" section above to upgrade when ready. +
)} diff --git a/services/custom-example/src/wagmi.ts b/services/custom-example/src/wagmi.ts index c33a404..a149bd6 100644 --- a/services/custom-example/src/wagmi.ts +++ b/services/custom-example/src/wagmi.ts @@ -6,7 +6,14 @@ import { createBundlerClient } from 'viem/account-abstraction'; import { createConfig } from 'wagmi'; import type { Chain } from 'wagmi/chains'; import { base, baseSepolia, hardhat } from 'wagmi/chains'; -import { config as envConfig, type SupportedEntryPointVersion, getFactoryAddress, getPaymasterAddress } from './config'; +import { + config as envConfig, + type SupportedEntryPointVersion, + getFactoryAddress, + getPaymasterAddress, + getProxyFactoryAddress, + getEntryPointPaymasterAddress +} from './config'; import { gianoInjection } from './giano-injection'; console.log('Using config:', envConfig); @@ -114,13 +121,16 @@ export function createVersionSpecificBundlerClient(entryPointVersion: SupportedE export function createGianoProviderWithVersion(entryPointVersion: SupportedEntryPointVersion = envConfig.defaultEntryPointVersion) { console.log('๐Ÿ”ง Creating Giano Provider with EntryPoint version:', entryPointVersion); - // Get version-specific addresses - const factoryAddress = getFactoryAddress(entryPointVersion); - const paymasterAddress = getPaymasterAddress(entryPointVersion); - console.log(' ๐Ÿญ Using factory address:', factoryAddress, 'for version:', entryPointVersion); - console.log(' ๐Ÿ’ฐ Using paymaster address:', paymasterAddress, 'for version:', entryPointVersion); + // PROXY UPGRADE PATTERN: Always use the same factory (deploys V07 proxies) + // Users upgrade implementations later via upgradeToAndCall() + const factoryAddress = getProxyFactoryAddress(); + const paymasterAddress = getEntryPointPaymasterAddress(entryPointVersion); + + console.log(' ๐Ÿญ Using proxy factory address:', factoryAddress); + console.log(' ๐Ÿ’ฐ Using paymaster address:', paymasterAddress, 'for EntryPoint version:', entryPointVersion); + console.log(' ๐Ÿ“ Note: All wallets start with V07 implementation (upgradeable to V08)'); - // Get version-specific bundler client + // Get version-specific bundler client (this affects which EntryPoint the bundler uses) const versionSpecificBundler = createVersionSpecificBundlerClient(entryPointVersion); return createGianoProvider({ @@ -130,7 +140,7 @@ export function createGianoProviderWithVersion(entryPointVersion: SupportedEntry initialChainId: configMap[envConfig.configKey].chain.id, injection: gianoInjection, gianoSmartWalletFactoryAddress: factoryAddress as Hex, - entryPointVersion, // ๐ŸŽฏ Pass the EntryPoint version here + entryPointVersion, // ๐ŸŽฏ This now affects bundler configuration, not wallet creation }); }