From b0f8d44b3a2f1d0f83c6e404f0063585a15f0556 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Thu, 10 Apr 2025 00:08:56 +0530 Subject: [PATCH 1/7] CSM endpoint --- .../run-tab/src/lib/actions/account.ts | 74 +++++++++++-------- .../run-tab/src/lib/components/account.tsx | 34 ++++----- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index d2e46caf51e..1ec89445b96 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -6,7 +6,7 @@ import { toChecksumAddress } from '@ethereumjs/util' import { SmartAccount } from "../types" import "viem/window" import { custom, createWalletClient, createPublicClient, http } from "viem" -import { sepolia } from "viem/chains" +import * as chains from "viem/chains" import { entryPoint07Address } from "viem/account-abstraction" const { createSmartAccountClient } = require("permissionless") /* eslint-disable-line @typescript-eslint/no-var-requires */ const { toSafeSmartAccount } = require("permissionless/accounts") /* eslint-disable-line @typescript-eslint/no-var-requires */ @@ -108,12 +108,47 @@ export const createNewBlockchainAccount = async (plugin: RunTab, dispatch: React ) } +const createSafeSmartAccount = async(safeAccount, toAddress, usePaymaster, chainObj) => { + const PIMLICO_API_KEY ='' + const chainName = chainObj.name + const BUNDLER_URL = `https://api.pimlico.io/v2/${chainName}/rpc?apikey=${PIMLICO_API_KEY}` + const paymasterClient = createPimlicoClient({ + transport: http(BUNDLER_URL), + entryPoint: { + address: entryPoint07Address, + version: "0.7", + }, + }) + + console.log('paymasterClient--->', paymasterClient) // api key is shown + + const saClient = createSmartAccountClient({ + account: safeAccount, + chainObj, + paymaster: paymasterClient, + bundlerTransport: http(BUNDLER_URL), + userOperation: { + estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast, + } + }) + console.log('saClient--->', saClient) // api key is shown + + // Make a dummy tx to force smart account deployment + const useropHash = await saClient.sendUserOperation({ + calls: [{ + to: toAddress, + value: 0 + }] + }) + await saClient.waitForUserOperationReceipt({ hash: useropHash }) +} + export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatch) => { const localStorageKey = 'smartAccounts' const PUBLIC_NODE_URL = "https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9" - const PIMLICO_API_KEY ='' - const BUNDLER_URL = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${PIMLICO_API_KEY}` const safeAddresses: string[] = Object.keys(plugin.REACT_API.smartAccounts) + const network = 'sepolia' + const chain = chains[network] let salt // @ts-ignore @@ -121,12 +156,12 @@ export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatc const walletClient = createWalletClient({ account, - chain: sepolia, + chain, transport: custom(window.ethereum!), }) const publicClient = createPublicClient({ - chain: sepolia, + chain, transport: http(PUBLIC_NODE_URL) // choose any provider here }) @@ -147,33 +182,8 @@ export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatc saltNonce: salt, version: "1.4.1" }) - - const paymasterClient = createPimlicoClient({ - transport: http(BUNDLER_URL), - entryPoint: { - address: entryPoint07Address, - version: "0.7", - }, - }) - - const saClient = createSmartAccountClient({ - account: safeAccount, - sepolia, - paymaster: paymasterClient, - bundlerTransport: http(BUNDLER_URL), - userOperation: { - estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast, - } - }) - // Make a dummy tx to force smart account deployment - const useropHash = await saClient.sendUserOperation({ - calls: [{ - to: "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44", - value: 0 - }] - }) - await saClient.waitForUserOperationReceipt({ hash: useropHash }) - + await createSafeSmartAccount(safeAccount, '0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44', true, chain) + // TO verify creation, check if there is a contract code at this address const safeAddress = safeAccount.address const sAccount: SmartAccount = { diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index b02b39b2b99..07fc2c1ab0b 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -31,23 +31,23 @@ export function AccountUI(props: AccountProps) { }, [accounts, selectedAccount]) // Uncomment this when we want to show 'Create Smart Account' button - // useEffect(() => { - // if (smartAccounts.length > 0 && networkName.includes('Sepolia')) { - // if(smartAccounts.includes(selectedAccount)) { - // setSmartAccountSelected(true) - // setEnableCSM(false) - // ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA - // } - // else { - // setSmartAccountSelected(false) - // setEnableCSM(true) - // ownerEOA.current = null - // } - // } else { - // setEnableCSM(false) - // setSmartAccountSelected(false) - // } - // }, [selectedAccount]) + useEffect(() => { + if (smartAccounts.length > 0 && networkName.includes('Sepolia')) { + if(smartAccounts.includes(selectedAccount)) { + setSmartAccountSelected(true) + setEnableCSM(false) + ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA + } + else { + setSmartAccountSelected(false) + setEnableCSM(true) + ownerEOA.current = null + } + } else { + setEnableCSM(false) + setSmartAccountSelected(false) + } + }, [selectedAccount]) useEffect(() => { props.setAccount('') From b23012a18a2003c14c894945b034b383dadb9d2d Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Sat, 12 Apr 2025 00:46:12 +0530 Subject: [PATCH 2/7] hit endpoint --- .../run-tab/src/lib/actions/account.ts | 72 ++++++------------- 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index 1ec89445b96..15effcd49c8 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -4,6 +4,7 @@ import { clearInstances, setAccount, setExecEnv } from "./actions" import { displayNotification, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setMatchPassphrase, setPassphrase } from "./payload" import { toChecksumAddress } from '@ethereumjs/util' import { SmartAccount } from "../types" +import axios from "axios" import "viem/window" import { custom, createWalletClient, createPublicClient, http } from "viem" import * as chains from "viem/chains" @@ -108,44 +109,10 @@ export const createNewBlockchainAccount = async (plugin: RunTab, dispatch: React ) } -const createSafeSmartAccount = async(safeAccount, toAddress, usePaymaster, chainObj) => { - const PIMLICO_API_KEY ='' - const chainName = chainObj.name - const BUNDLER_URL = `https://api.pimlico.io/v2/${chainName}/rpc?apikey=${PIMLICO_API_KEY}` - const paymasterClient = createPimlicoClient({ - transport: http(BUNDLER_URL), - entryPoint: { - address: entryPoint07Address, - version: "0.7", - }, - }) - - console.log('paymasterClient--->', paymasterClient) // api key is shown - - const saClient = createSmartAccountClient({ - account: safeAccount, - chainObj, - paymaster: paymasterClient, - bundlerTransport: http(BUNDLER_URL), - userOperation: { - estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast, - } - }) - console.log('saClient--->', saClient) // api key is shown - - // Make a dummy tx to force smart account deployment - const useropHash = await saClient.sendUserOperation({ - calls: [{ - to: toAddress, - value: 0 - }] - }) - await saClient.waitForUserOperationReceipt({ hash: useropHash }) -} - export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatch) => { const localStorageKey = 'smartAccounts' const PUBLIC_NODE_URL = "https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9" + const toAddress = "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44" const safeAddresses: string[] = Object.keys(plugin.REACT_API.smartAccounts) const network = 'sepolia' const chain = chains[network] @@ -182,24 +149,25 @@ export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatc saltNonce: salt, version: "1.4.1" }) - await createSafeSmartAccount(safeAccount, '0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44', true, chain) + const response = await axios.post(`http://localhost:4000/account-abstraction/createSafeSmartAccount`, { safeAccountObj: safeAccount, toAddress, usePaymaster: true, chainObj: chain }) + console.log('response', response) // TO verify creation, check if there is a contract code at this address - const safeAddress = safeAccount.address - - const sAccount: SmartAccount = { - address : safeAccount.address, - salt, - ownerEOA: account, - timestamp: Date.now() - } - plugin.REACT_API.smartAccounts[safeAddress] = sAccount - // Save smart accounts in local storage - const smartAccountsStr = localStorage.getItem(localStorageKey) - const smartAccountsObj = JSON.parse(smartAccountsStr) - smartAccountsObj[plugin.REACT_API.chainId] = plugin.REACT_API.smartAccounts - localStorage.setItem(localStorageKey, JSON.stringify(smartAccountsObj)) - - return plugin.call('notification', 'toast', `Safe account ${safeAccount.address} created for owner ${account}`) + // const safeAddress = safeAccount.address + + // const sAccount: SmartAccount = { + // address : safeAccount.address, + // salt, + // ownerEOA: account, + // timestamp: Date.now() + // } + // plugin.REACT_API.smartAccounts[safeAddress] = sAccount + // // Save smart accounts in local storage + // const smartAccountsStr = localStorage.getItem(localStorageKey) + // const smartAccountsObj = JSON.parse(smartAccountsStr) + // smartAccountsObj[plugin.REACT_API.chainId] = plugin.REACT_API.smartAccounts + // localStorage.setItem(localStorageKey, JSON.stringify(smartAccountsObj)) + + // return plugin.call('notification', 'toast', `Safe account ${safeAccount.address} created for owner ${account}`) } catch (error) { console.error('Failed to create safe smart account: ', error) return plugin.call('notification', 'toast', `Failed to create safe smart account !!!`) From 89dcf748a3cd84cc6f306ca7b5e757a3ce4715e5 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 22 Apr 2025 14:54:26 +0530 Subject: [PATCH 3/7] bundler proxy for csm --- .../run-tab/src/lib/actions/account.ts | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index 15effcd49c8..ad86b0c62f1 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -112,10 +112,12 @@ export const createNewBlockchainAccount = async (plugin: RunTab, dispatch: React export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatch) => { const localStorageKey = 'smartAccounts' const PUBLIC_NODE_URL = "https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9" - const toAddress = "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44" + const toAddress = "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44" // can be zero address too const safeAddresses: string[] = Object.keys(plugin.REACT_API.smartAccounts) const network = 'sepolia' const chain = chains[network] + const BUNDLER_URL = `https://pimlico.remixproject.org/api/proxy/${chain.id}` + let salt // @ts-ignore @@ -149,25 +151,51 @@ export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatc saltNonce: salt, version: "1.4.1" }) - const response = await axios.post(`http://localhost:4000/account-abstraction/createSafeSmartAccount`, { safeAccountObj: safeAccount, toAddress, usePaymaster: true, chainObj: chain }) - console.log('response', response) + + + const paymasterClient = createPimlicoClient({ + transport: http(BUNDLER_URL), + entryPoint: { + address: entryPoint07Address, + version: "0.7", + }, + }) + + const saClient = createSmartAccountClient({ + account: safeAccount, + chain, + paymaster: paymasterClient, + bundlerTransport: http(BUNDLER_URL), + userOperation: { + estimateFeesPerGas: async () => (await paymasterClient.getUserOperationGasPrice()).fast, + } + }) + // Make a dummy tx to force smart account deployment + const useropHash = await saClient.sendUserOperation({ + calls: [{ + to: toAddress, + value: 0 + }] + }) + await saClient.waitForUserOperationReceipt({ hash: useropHash }) + // TO verify creation, check if there is a contract code at this address - // const safeAddress = safeAccount.address - - // const sAccount: SmartAccount = { - // address : safeAccount.address, - // salt, - // ownerEOA: account, - // timestamp: Date.now() - // } - // plugin.REACT_API.smartAccounts[safeAddress] = sAccount - // // Save smart accounts in local storage - // const smartAccountsStr = localStorage.getItem(localStorageKey) - // const smartAccountsObj = JSON.parse(smartAccountsStr) - // smartAccountsObj[plugin.REACT_API.chainId] = plugin.REACT_API.smartAccounts - // localStorage.setItem(localStorageKey, JSON.stringify(smartAccountsObj)) - - // return plugin.call('notification', 'toast', `Safe account ${safeAccount.address} created for owner ${account}`) + const safeAddress = safeAccount.address + + const sAccount: SmartAccount = { + address : safeAccount.address, + salt, + ownerEOA: account, + timestamp: Date.now() + } + plugin.REACT_API.smartAccounts[safeAddress] = sAccount + // Save smart accounts in local storage + const smartAccountsStr = localStorage.getItem(localStorageKey) + const smartAccountsObj = JSON.parse(smartAccountsStr) + smartAccountsObj[plugin.REACT_API.chainId] = plugin.REACT_API.smartAccounts + localStorage.setItem(localStorageKey, JSON.stringify(smartAccountsObj)) + + return plugin.call('notification', 'toast', `Safe account ${safeAccount.address} created for owner ${account}`) } catch (error) { console.error('Failed to create safe smart account: ', error) return plugin.call('notification', 'toast', `Failed to create safe smart account !!!`) From f197abdc8e388e6830c9546e09350b0d6b8820ad Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 22 Apr 2025 14:58:55 +0530 Subject: [PATCH 4/7] proxy url for interaction --- libs/remix-lib/src/execution/txRunnerWeb3.ts | 3 +-- libs/remix-ui/run-tab/src/lib/actions/account.ts | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index 1e2c6df8dce..ac34e87c500 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -230,11 +230,10 @@ export class TxRunnerWeb3 { async sendUserOp (tx) { const localStorageKey = 'smartAccounts' const PUBLIC_NODE_URL = "https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9" - const PIMLICO_API_KEY ='' - const BUNDLER_URL = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${PIMLICO_API_KEY}` const determiniticProxyAddress = "0x4e59b44847b379578588920cA78FbF26c0B4956C" const network = 'sepolia' const chain = chains[network] + const BUNDLER_URL = `https://pimlico.remixproject.org/api/proxy/${chain.id}` // Check that saOwner is there in MM addresses let smartAccountsObj = localStorage.getItem(localStorageKey) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index ad86b0c62f1..a88f6157548 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -4,7 +4,6 @@ import { clearInstances, setAccount, setExecEnv } from "./actions" import { displayNotification, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setMatchPassphrase, setPassphrase } from "./payload" import { toChecksumAddress } from '@ethereumjs/util' import { SmartAccount } from "../types" -import axios from "axios" import "viem/window" import { custom, createWalletClient, createPublicClient, http } from "viem" import * as chains from "viem/chains" From 428b7affb5dfb3d4d7ec5a87aeb408809cebc2c0 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 22 Apr 2025 19:03:54 +0530 Subject: [PATCH 5/7] fix initial condition --- libs/remix-ui/run-tab/src/lib/components/account.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index 07fc2c1ab0b..3d8dfcdb59f 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -32,8 +32,8 @@ export function AccountUI(props: AccountProps) { // Uncomment this when we want to show 'Create Smart Account' button useEffect(() => { - if (smartAccounts.length > 0 && networkName.includes('Sepolia')) { - if(smartAccounts.includes(selectedAccount)) { + if (networkName.includes('Sepolia')) { + if(smartAccounts.length > 0 && smartAccounts.includes(selectedAccount)) { setSmartAccountSelected(true) setEnableCSM(false) ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA From 246abc2fed2f3c36217f6823ed03b90cf008a32b Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Tue, 22 Apr 2025 19:05:55 +0530 Subject: [PATCH 6/7] fix linting --- libs/remix-ui/run-tab/src/lib/actions/account.ts | 1 - libs/remix-ui/run-tab/src/lib/components/account.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index a88f6157548..1295ea86792 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -151,7 +151,6 @@ export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatc version: "1.4.1" }) - const paymasterClient = createPimlicoClient({ transport: http(BUNDLER_URL), entryPoint: { diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index 3d8dfcdb59f..5d92314d126 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -33,7 +33,7 @@ export function AccountUI(props: AccountProps) { // Uncomment this when we want to show 'Create Smart Account' button useEffect(() => { if (networkName.includes('Sepolia')) { - if(smartAccounts.length > 0 && smartAccounts.includes(selectedAccount)) { + if (smartAccounts.length > 0 && smartAccounts.includes(selectedAccount)) { setSmartAccountSelected(true) setEnableCSM(false) ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA From e8a0023b798e491c8a5f37ad06c9b4222a4a1db0 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Wed, 23 Apr 2025 13:10:42 +0530 Subject: [PATCH 7/7] comment again --- .../run-tab/src/lib/actions/account.ts | 2 +- .../run-tab/src/lib/components/account.tsx | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/actions/account.ts b/libs/remix-ui/run-tab/src/lib/actions/account.ts index 1295ea86792..5f2ad03e5fa 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/account.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/account.ts @@ -111,7 +111,7 @@ export const createNewBlockchainAccount = async (plugin: RunTab, dispatch: React export const createSmartAccount = async (plugin: RunTab, dispatch: React.Dispatch) => { const localStorageKey = 'smartAccounts' const PUBLIC_NODE_URL = "https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9" - const toAddress = "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44" // can be zero address too + const toAddress = "0xAFdAC33F6F134D46bAbE74d9125F3bf8e8AB3a44" // A dummy zero value tx is made to this address to create existence of smart account const safeAddresses: string[] = Object.keys(plugin.REACT_API.smartAccounts) const network = 'sepolia' const chain = chains[network] diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index 5d92314d126..f09de3193e8 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -31,23 +31,23 @@ export function AccountUI(props: AccountProps) { }, [accounts, selectedAccount]) // Uncomment this when we want to show 'Create Smart Account' button - useEffect(() => { - if (networkName.includes('Sepolia')) { - if (smartAccounts.length > 0 && smartAccounts.includes(selectedAccount)) { - setSmartAccountSelected(true) - setEnableCSM(false) - ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA - } - else { - setSmartAccountSelected(false) - setEnableCSM(true) - ownerEOA.current = null - } - } else { - setEnableCSM(false) - setSmartAccountSelected(false) - } - }, [selectedAccount]) + // useEffect(() => { + // if (networkName.includes('Sepolia')) { + // if (smartAccounts.length > 0 && smartAccounts.includes(selectedAccount)) { + // setSmartAccountSelected(true) + // setEnableCSM(false) + // ownerEOA.current = props.runTabPlugin.REACT_API.smartAccounts[selectedAccount].ownerEOA + // } + // else { + // setSmartAccountSelected(false) + // setEnableCSM(true) + // ownerEOA.current = null + // } + // } else { + // setEnableCSM(false) + // setSmartAccountSelected(false) + // } + // }, [selectedAccount]) useEffect(() => { props.setAccount('')