From 9e5035b3c6954a6499978a16207858b906d9fc21 Mon Sep 17 00:00:00 2001 From: kanth Date: Thu, 29 May 2025 19:07:54 +0530 Subject: [PATCH 01/22] feat: set HookMultiplexer address in EtherspotWalletAPI --- src/sdk/base/EtherspotWalletAPI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 2b59f2c..5d4c98a 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -234,7 +234,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI { } const validators: BootstrapConfig[] = makeBootstrapConfig(this.validatorAddress, '0x'); const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); - const hook: BootstrapConfig = _makeBootstrapConfig(ADDRESS_ZERO, '0x'); + const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, '0x'); const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); const initMSAData = encodeFunctionData({ From f6454f19926843da5e99391d1e032959b8c20f92 Mon Sep 17 00:00:00 2001 From: kanth Date: Thu, 29 May 2025 19:29:11 +0530 Subject: [PATCH 02/22] feat: add hmpInitData while adding HookMultiplexer as defaultHook --- src/sdk/base/BaseAccountAPI.ts | 2 ++ src/sdk/base/EtherspotWalletAPI.ts | 7 +++++- src/sdk/network/constants.ts | 36 ++++++++++++++++++++++++++++++ src/sdk/network/interfaces.ts | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/sdk/base/BaseAccountAPI.ts b/src/sdk/base/BaseAccountAPI.ts index a09d534..a39e23a 100644 --- a/src/sdk/base/BaseAccountAPI.ts +++ b/src/sdk/base/BaseAccountAPI.ts @@ -57,6 +57,7 @@ export abstract class BaseAccountAPI { factoryAddress?: string; validatorAddress?: string; hookMultiplexerAddress?: string; + credibleAccountModuleAddress?: string; wallet: WalletProviderLike; publicClient: PublicClient; @@ -98,6 +99,7 @@ export abstract class BaseAccountAPI { this.publicClient = params.publicClient; this.validatorAddress = params.optionsLike?.multipleOwnerECDSAValidatorAddress ?? Networks[params.optionsLike.chainId]?.contracts?.multipleOwnerECDSAValidator ?? DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS; this.hookMultiplexerAddress = Networks[params.optionsLike.chainId]?.contracts?.hookMultiPlexer || AddressZero; + this.credibleAccountModuleAddress = Networks[params.optionsLike.chainId]?.contracts?.credibleAccountModule || AddressZero; } get error$(): ErrorSubject { diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 5d4c98a..12b76a5 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -7,6 +7,7 @@ import { DEFAULT_BOOTSTRAP_ADDRESS, DEFAULT_QUERY_PAGE_SIZE, Networks } from '.. import { BigNumber, BigNumberish } from '../types/bignumber.js'; import { BaseAccountAPI, BaseApiParams } from './BaseAccountAPI.js'; import { BootstrapConfig, _makeBootstrapConfig, makeBootstrapConfig } from './Bootstrap.js'; +import { getHookMultiPlexerInitData } from '../../../examples/pulse/utils.js'; // Creating a constant for the sentinel address using viem const SENTINEL_ADDRESS = getAddress("0x0000000000000000000000000000000000000001"); @@ -234,7 +235,11 @@ export class EtherspotWalletAPI extends BaseAccountAPI { } const validators: BootstrapConfig[] = makeBootstrapConfig(this.validatorAddress, '0x'); const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); - const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, '0x'); + + //Get HookMultiPlexer init data with CredibleAccountHook as global subhook + let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); + const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, hmpInitData); + const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); const initMSAData = encodeFunctionData({ diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 8577b01..7074ab1 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -102,6 +102,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [11155111]: { @@ -115,6 +116,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [10]: { @@ -129,6 +131,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [137]: { @@ -142,6 +145,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [42161]: { @@ -155,6 +159,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [1]: { @@ -168,6 +173,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [10200]: { @@ -181,6 +187,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [122]: { @@ -194,6 +201,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [123]: { @@ -208,6 +216,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [100]: { @@ -221,6 +230,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [2357]: { @@ -234,6 +244,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [30]: { @@ -247,6 +258,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [31]: { @@ -260,6 +272,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [5000]: { @@ -273,6 +286,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [5003]: { @@ -286,6 +300,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [43114]: { @@ -299,6 +314,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [8453]: { @@ -312,6 +328,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [56]: { @@ -325,6 +342,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [97]: { @@ -338,6 +356,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [43113]: { @@ -351,6 +370,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [59144]: { @@ -364,6 +384,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [59140]: { @@ -377,6 +398,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [114]: { @@ -390,6 +412,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [14]: { @@ -403,6 +426,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [534351]: { @@ -416,6 +440,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [534352]: { @@ -429,6 +454,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [11155420]: { @@ -442,6 +468,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [28122024]: { @@ -455,6 +482,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [888888888]: { @@ -468,6 +496,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [80002]: { @@ -481,6 +510,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [421614]: { @@ -494,6 +524,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [51]: { @@ -507,6 +538,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [50]: { @@ -520,6 +552,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [44787]: { @@ -533,6 +566,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [42220]: { @@ -546,6 +580,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, [79479957]: { @@ -572,6 +607,7 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '', }, }, }; diff --git a/src/sdk/network/interfaces.ts b/src/sdk/network/interfaces.ts index 68eabf4..0791a89 100644 --- a/src/sdk/network/interfaces.ts +++ b/src/sdk/network/interfaces.ts @@ -17,5 +17,6 @@ export interface NetworkConfig { multipleOwnerECDSAValidator: string; erc20SessionKeyValidator: string; hookMultiPlexer: string; + credibleAccountModule: string; }; }; From 005667c3d7258b8f3f49b3f19751012536ff0bfb Mon Sep 17 00:00:00 2001 From: kanth Date: Thu, 29 May 2025 19:43:22 +0530 Subject: [PATCH 03/22] feat: enhance adding multiple validators or modules while preparing BootStrapConfig entries --- src/sdk/base/Bootstrap.ts | 32 ++++++++++++++++++++++++++++++ src/sdk/base/EtherspotWalletAPI.ts | 4 ++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/sdk/base/Bootstrap.ts b/src/sdk/base/Bootstrap.ts index 5e43c1d..7b9c67c 100644 --- a/src/sdk/base/Bootstrap.ts +++ b/src/sdk/base/Bootstrap.ts @@ -37,3 +37,35 @@ export function makeBootstrapConfig(module: string, data: string): BootstrapConf config.push(newConfig); return config; } + +export function makeBootstrapConfigForModules(modules: string[], moduleInitDataItems: string[]): BootstrapConfig[] { + const config: BootstrapConfig[] = []; + + for (const [index, moduleEntry] of modules.entries()) { + + if (!moduleEntry) { + throw new Error(`Module name is not provided for index ${index}.`); + } + + const data = moduleInitDataItems[index]; + + if (!data) { + throw new Error(`Module init data for module ${moduleEntry} is not provided.`); + } + + const encodedFunctionData = encodeFunctionData({ + functionName: 'onInstall', + abi: parseAbi(modulesAbi), + args: [data], + }); + + const newConfig: BootstrapConfig = { + module: moduleEntry, + data: encodedFunctionData, + }; + + config.push(newConfig); + } + + return config; +} \ No newline at end of file diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 12b76a5..5715781 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -6,7 +6,7 @@ import { getViemAddress } from '../common/utils/viem-utils.js'; import { DEFAULT_BOOTSTRAP_ADDRESS, DEFAULT_QUERY_PAGE_SIZE, Networks } from '../network/constants.js'; import { BigNumber, BigNumberish } from '../types/bignumber.js'; import { BaseAccountAPI, BaseApiParams } from './BaseAccountAPI.js'; -import { BootstrapConfig, _makeBootstrapConfig, makeBootstrapConfig } from './Bootstrap.js'; +import { BootstrapConfig, _makeBootstrapConfig, makeBootstrapConfig, makeBootstrapConfigForModules } from './Bootstrap.js'; import { getHookMultiPlexerInitData } from '../../../examples/pulse/utils.js'; // Creating a constant for the sentinel address using viem @@ -233,7 +233,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI { if (!this.validatorAddress) { throw new Error('Validator address not found'); } - const validators: BootstrapConfig[] = makeBootstrapConfig(this.validatorAddress, '0x'); + const validators: BootstrapConfig[] = makeBootstrapConfigForModules([this.validatorAddress, this.credibleAccountModuleAddress as Hex] , ['0x', '0x']); const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook From 697aa5c525ecd36b4c3b71838811017f78606535 Mon Sep 17 00:00:00 2001 From: kanth Date: Thu, 29 May 2025 21:25:55 +0530 Subject: [PATCH 04/22] feat: example script to setup HMP and CAM on a fresh account --- .../credible-account-ecosystem-install.ts | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 examples/modules/credible-account-ecosystem-install.ts diff --git a/examples/modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-ecosystem-install.ts new file mode 100644 index 0000000..d84e2a4 --- /dev/null +++ b/examples/modules/credible-account-ecosystem-install.ts @@ -0,0 +1,116 @@ +import { printOp } from '../../src/sdk/common/OperationUtils'; +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../src/sdk/common'; +import { encodeAbiParameters, encodeFunctionData, Hex, parseAbi } from 'viem'; +import { generateModularSDKInstance } from '../helpers/sdk-helper'; +import { getHookMultiPlexerInitData } from '../pulse/utils'; +import { accountAbi } from '../../src/sdk/common/abis'; + +dotenv.config(); + +const bundlerApiKey = 'etherspot_public_key'; +// const CHAIN_ID = '84532'; +// const HOOK_MULTIPLEXER_ADDRESS = '0x61c58064640C752e950647c8AFDf1E2C0a098251'; +// const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0x373aBcF1EA9e5802778E32870e7f72C8A6a90349'; +// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0xbb4D635B26a565B3722B4683459A27D3747101Ab'; + + +// const CHAIN_ID = '11155111'; +// const HOOK_MULTIPLEXER_ADDRESS = '0x0d1F23CA4092eBF61291622616a73008d5d7e9FF'; +// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0x56BE864234F5710C00868e29e1fbB76ad4f234e3'; +// const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0xFa970f9Bd071999FD54F7fDD80cA17965Fa8f5b6'; + +const CHAIN_ID = '8453'; +const HOOK_MULTIPLEXER_ADDRESS = '0xDcA918dd23456d321282DF9507F6C09A50522136'; +const RESOURCE_LOCK_VALIDATOR_ADDRESS = ''; +const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0xDcA918dd23456d321282DF9507F6C09A50522136'; + +// const CHAIN_ID = '10'; +// const HOOK_MULTIPLEXER_ADDRESS = ''; +// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = ''; +// const RESOURCE_LOCK_VALIDATOR_ADDRESS = ''; + +// tsx examples/modules/credible-account-ecosystem-install.ts +async function main() { + // Init SDK + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + Number(CHAIN_ID), + bundlerApiKey, + ); + + // Get counterfactual of ModularEtherspotWallet... + const address: Hex = (await modularSdk.getCounterFactualAddress()) as Hex; + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + // Get native balance + const balance = await modularSdk.getNativeBalance(); + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet native balance: ${balance}`); + // Clear existing UserOps from batch + await modularSdk.clearUserOpsFromBatch(); + + /*////////////////////////////////////////////////////////////// + INSTALL HOOK MULTIPLEXER WITH CREDIBLE ACCOUNT MODULE - AS HOOK + //////////////////////////////////////////////////////////////*/ + + //Get HookMultiPlexer init data with CredibleAccountHook as global subhook + let hmpInitData = getHookMultiPlexerInitData([CREDIBLE_ACCOUNT_MODULE_ADDRESS]); + const hmpInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, hmpInitData], + }); + // // Add UserOp to batch + await modularSdk.addUserOpsToBatch({ to: address, data: hmpInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + INSTALL CREDIBLE ACCOUNT MODULE - AS VALIDATOR + //////////////////////////////////////////////////////////////*/ + + //Get CredibleAccountValidator init data + let cavInitData = encodeAbiParameters([{ type: 'uint256' }], [BigInt(MODULE_TYPE.VALIDATOR)]); + const cavInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.VALIDATOR), CREDIBLE_ACCOUNT_MODULE_ADDRESS, cavInitData], + }); + // Add UserOp to batch + await modularSdk.addUserOpsToBatch({ to: address, data: cavInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + INSTALL RESOURCE LOCK VALIDATOR + //////////////////////////////////////////////////////////////*/ + + // Get CredibleAccountValidator init data + // let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); + // const rlvInstallCalldata = encodeFunctionData({ + // abi: parseAbi(accountAbi), + // functionName: 'installModule', + // args: [BigInt(MODULE_TYPE.VALIDATOR), RESOURCE_LOCK_VALIDATOR_ADDRESS, rlvInitData], + // }); + // // Add UserOp to batch + // await modularSdk.addUserOpsToBatch({ to: address, data: rlvInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + ESTIMATE/SEND USER OP + //////////////////////////////////////////////////////////////*/ + + // Estimate UserOp + const op = await modularSdk.estimate(); + console.log(`Estimate UserOp: ${await printOp(op)}`); + // Send UserOp + const uoHash = await modularSdk.send(op); + console.log(`UserOpHash: ${uoHash}`); + // Await transaction hash + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 1200000; // 1 minute timeout + while (userOpsReceipt == null && Date.now() < timeout) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); From febc6e8b3550cd0f4e9114c6f62cddc1bea660da Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Tue, 3 Jun 2025 13:04:44 +0530 Subject: [PATCH 05/22] fixes for init code generation --- examples/pulse/utils.ts | 15 ++------------- src/sdk/base/EtherspotWalletAPI.ts | 16 +++++++++++++++- src/sdk/network/constants.ts | 6 +++--- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/examples/pulse/utils.ts b/examples/pulse/utils.ts index f0e8bd2..13c9ae7 100644 --- a/examples/pulse/utils.ts +++ b/examples/pulse/utils.ts @@ -45,17 +45,6 @@ export function getHookMultiPlexerInitData( delegatecallHooks, sigHooks, targetSigHooks - ] as any); - - console.log('Encoded Data:', encodedData); - - const hookMultiplexerInitData = encodeFunctionData({ - abi: HookMultiplexer, - args: [encodedData], - functionName: 'onInstall', - }); - - console.log('Hook Multiplexer Init Data:', hookMultiplexerInitData); - - return hookMultiplexerInitData; + ]); + return encodedData; } \ No newline at end of file diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 5715781..b49918c 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -233,7 +233,21 @@ export class EtherspotWalletAPI extends BaseAccountAPI { if (!this.validatorAddress) { throw new Error('Validator address not found'); } - const validators: BootstrapConfig[] = makeBootstrapConfigForModules([this.validatorAddress, this.credibleAccountModuleAddress as Hex] , ['0x', '0x']); + + const validators: BootstrapConfig[] = makeBootstrapConfigForModules( + [ + this.validatorAddress, + this.credibleAccountModuleAddress as Hex + ] , + [ + '0x', + encodeAbiParameters( + parseAbiParameters('uint256'), + [BigInt(MODULE_TYPE.VALIDATOR)] + ) + ] + ); + const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 7074ab1..3e2d5e1 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -98,11 +98,11 @@ export const Networks: { contracts: { entryPoint: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', walletFactory: '0x38CC0EDdD3a944CA17981e0A19470d2298B8d43a', - bootstrap: '0xCF2808eA7d131d96E5C73Eb0eCD8Dc84D33905C7', + bootstrap: '0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', - hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', + hookMultiPlexer: '0xB56335BaEB331DF3955ac4d6841ac6DdA5b14cb4', + credibleAccountModule: '0xF34fEBDCc36D7246498C56bEfc10bE5dC694C494', }, }, [11155111]: { From 223592fd47244d1f3137385917f9334656354f07 Mon Sep 17 00:00:00 2001 From: kanth Date: Tue, 3 Jun 2025 14:33:18 +0530 Subject: [PATCH 06/22] fix: refactor getHookMultiplexerInitData to EtherspotWalletAPI --- src/sdk/base/EtherspotWalletAPI.ts | 39 ++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index b49918c..e24e684 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -7,7 +7,6 @@ import { DEFAULT_BOOTSTRAP_ADDRESS, DEFAULT_QUERY_PAGE_SIZE, Networks } from '.. import { BigNumber, BigNumberish } from '../types/bignumber.js'; import { BaseAccountAPI, BaseApiParams } from './BaseAccountAPI.js'; import { BootstrapConfig, _makeBootstrapConfig, makeBootstrapConfig, makeBootstrapConfigForModules } from './Bootstrap.js'; -import { getHookMultiPlexerInitData } from '../../../examples/pulse/utils.js'; // Creating a constant for the sentinel address using viem const SENTINEL_ADDRESS = getAddress("0x0000000000000000000000000000000000000001"); @@ -37,6 +36,12 @@ export type FallbackInfo = { handlerAddress: string; }; + +export interface SigHookInit { + sig: string; + subHooks: Hex[]; +} + /** * An implementation of the BaseAccountAPI using the EtherspotWallet contract. * - contract deployer gets "entrypoint", "owner" addresses and "index" nonce @@ -251,7 +256,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI { const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook - let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); + let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : this.getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, hmpInitData); const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); @@ -448,4 +453,34 @@ export class EtherspotWalletAPI extends BaseAccountAPI { args: [executeMode, calldata], }); } + + getHookMultiPlexerInitData( + globalHooks: Hex[] = [], + valueHooks: Hex[] = [], + delegatecallHooks: Hex[] = [], + sigHooks: SigHookInit[] = [], + targetSigHooks: SigHookInit[] = [], + ): Hex { + const abiType = [ + { type: 'address[]' }, + { type: 'address[]' }, + { type: 'address[]' }, + { + type: 'tuple[]', + components: [{ type: 'bytes4' }, { type: 'address[]' }], + }, + { + type: 'tuple[]', + components: [{ type: 'bytes4' }, { type: 'address[]' }], + }, + ]; + const encodedData = encodeAbiParameters(abiType, [ + globalHooks, + valueHooks, + delegatecallHooks, + sigHooks, + targetSigHooks + ]); + return encodedData; + } } From 4310c8e272b1741a4b09df215241013920a7a71f Mon Sep 17 00:00:00 2001 From: kanth Date: Tue, 3 Jun 2025 14:37:56 +0530 Subject: [PATCH 07/22] feat: bumped the package version --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b249fd..d796013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [7.0.0] - 2025-06-03 +### Breaking Changes +- Updated HookMultiplexer, CredibleAccountModule and Bootstrap contract addresses for all chains +- getInitCode logic updated to include + - HookMultiplexer as defaultHook with CredibleAccountModule as globalHook in Multiplexer + - CredibleAccountModule to be installed as validator along with MultiSigECDSAModule +- Results in a change of precomputed modular account address. + + ## [6.1.0] - 2025-05-28 ### Breaking Changes - Changed contract address for Wallet Factory from `0x2A40091f044e48DEB5C0FCbc442E443F3341B451` to `0x38CC0EDdD3a944CA17981e0A19470d2298B8d43a`. diff --git a/package.json b/package.json index 099a50b..9192967 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@etherspot/modular-sdk", - "version": "6.1.0", + "version": "7.0.0", "description": "Etherspot Modular SDK - build with ERC-7579 smart accounts modules", "keywords": [ "ether", From c4963ccbf271a55a689ee951a4fd3fab1b9f32d6 Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Tue, 3 Jun 2025 15:58:38 +0530 Subject: [PATCH 08/22] minor fixes for build issues --- src/sdk/base/EtherspotWalletAPI.ts | 33 ++------------------------ src/sdk/common/getInitData.ts | 38 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index e24e684..fb33d31 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -7,6 +7,7 @@ import { DEFAULT_BOOTSTRAP_ADDRESS, DEFAULT_QUERY_PAGE_SIZE, Networks } from '.. import { BigNumber, BigNumberish } from '../types/bignumber.js'; import { BaseAccountAPI, BaseApiParams } from './BaseAccountAPI.js'; import { BootstrapConfig, _makeBootstrapConfig, makeBootstrapConfig, makeBootstrapConfigForModules } from './Bootstrap.js'; +import { getHookMultiPlexerInitData } from '../common/getInitData.js'; // Creating a constant for the sentinel address using viem const SENTINEL_ADDRESS = getAddress("0x0000000000000000000000000000000000000001"); @@ -256,7 +257,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI { const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook - let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : this.getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); + let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, hmpInitData); const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); @@ -453,34 +454,4 @@ export class EtherspotWalletAPI extends BaseAccountAPI { args: [executeMode, calldata], }); } - - getHookMultiPlexerInitData( - globalHooks: Hex[] = [], - valueHooks: Hex[] = [], - delegatecallHooks: Hex[] = [], - sigHooks: SigHookInit[] = [], - targetSigHooks: SigHookInit[] = [], - ): Hex { - const abiType = [ - { type: 'address[]' }, - { type: 'address[]' }, - { type: 'address[]' }, - { - type: 'tuple[]', - components: [{ type: 'bytes4' }, { type: 'address[]' }], - }, - { - type: 'tuple[]', - components: [{ type: 'bytes4' }, { type: 'address[]' }], - }, - ]; - const encodedData = encodeAbiParameters(abiType, [ - globalHooks, - valueHooks, - delegatecallHooks, - sigHooks, - targetSigHooks - ]); - return encodedData; - } } diff --git a/src/sdk/common/getInitData.ts b/src/sdk/common/getInitData.ts index 811a3d5..b477022 100644 --- a/src/sdk/common/getInitData.ts +++ b/src/sdk/common/getInitData.ts @@ -4,7 +4,8 @@ import { decodeFunctionData, parseAbi, slice, -} from 'viem' + encodeAbiParameters +} from 'viem'; import { InitialModules, Module } from './types.js' import { bootstrapAbi, factoryAbi } from './abis.js' @@ -46,3 +47,38 @@ export const getInitData = ({ fallbacks: initCallDataArgs[3] as Module[], } } + +export interface SigHookInit { + sig: string; + subHooks: Hex[]; +} + +export function getHookMultiPlexerInitData( + globalHooks: Hex[] = [], + valueHooks: Hex[] = [], + delegatecallHooks: Hex[] = [], + sigHooks: SigHookInit[] = [], + targetSigHooks: SigHookInit[] = [], +): Hex { + const abiType = [ + { type: 'address[]' }, + { type: 'address[]' }, + { type: 'address[]' }, + { + type: 'tuple[]', + components: [{ type: 'bytes4' }, { type: 'address[]' }], + }, + { + type: 'tuple[]', + components: [{ type: 'bytes4' }, { type: 'address[]' }], + }, + ]; + const encodedData = encodeAbiParameters(abiType, [ + globalHooks, + valueHooks, + delegatecallHooks, + sigHooks, + targetSigHooks + ] as any); + return encodedData; +} From 29c6100bbdee5ddc9dd44dd6550c9e4a8199e903 Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Wed, 4 Jun 2025 20:54:04 +0530 Subject: [PATCH 09/22] changes to add resource lock validator to init code --- src/sdk/base/BaseAccountAPI.ts | 3 +++ src/sdk/base/EtherspotWalletAPI.ts | 10 ++++--- src/sdk/network/constants.ts | 42 +++++++++++++++++++++++++++--- src/sdk/network/interfaces.ts | 1 + 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/sdk/base/BaseAccountAPI.ts b/src/sdk/base/BaseAccountAPI.ts index a39e23a..6db143e 100644 --- a/src/sdk/base/BaseAccountAPI.ts +++ b/src/sdk/base/BaseAccountAPI.ts @@ -58,6 +58,8 @@ export abstract class BaseAccountAPI { validatorAddress?: string; hookMultiplexerAddress?: string; credibleAccountModuleAddress?: string; + resourceLockValidatorAddress: string; + wallet: WalletProviderLike; publicClient: PublicClient; @@ -100,6 +102,7 @@ export abstract class BaseAccountAPI { this.validatorAddress = params.optionsLike?.multipleOwnerECDSAValidatorAddress ?? Networks[params.optionsLike.chainId]?.contracts?.multipleOwnerECDSAValidator ?? DEFAULT_MULTIPLE_OWNER_ECDSA_VALIDATOR_ADDRESS; this.hookMultiplexerAddress = Networks[params.optionsLike.chainId]?.contracts?.hookMultiPlexer || AddressZero; this.credibleAccountModuleAddress = Networks[params.optionsLike.chainId]?.contracts?.credibleAccountModule || AddressZero; + this.resourceLockValidatorAddress = Networks[params.optionsLike.chainId]?.contracts?.resourceLockValidator || AddressZero; } get error$(): ErrorSubject { diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index fb33d31..4675428 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -243,21 +243,25 @@ export class EtherspotWalletAPI extends BaseAccountAPI { const validators: BootstrapConfig[] = makeBootstrapConfigForModules( [ this.validatorAddress, - this.credibleAccountModuleAddress as Hex + this.credibleAccountModuleAddress as Hex, + this.resourceLockValidatorAddress ] , [ '0x', encodeAbiParameters( parseAbiParameters('uint256'), [BigInt(MODULE_TYPE.VALIDATOR)] - ) + ), + '0x' ] ); const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook - let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); + let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData( + [this.credibleAccountModuleAddress as Hex] + ); const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, hmpInitData); const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 3e2d5e1..b9d6252 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -103,6 +103,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xB56335BaEB331DF3955ac4d6841ac6DdA5b14cb4', credibleAccountModule: '0xF34fEBDCc36D7246498C56bEfc10bE5dC694C494', + resourceLockValidator: "0x9569FaD05892164ca3daf9a90f0590543eC97A7d", }, }, [11155111]: { @@ -112,11 +113,12 @@ export const Networks: { contracts: { entryPoint: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', walletFactory: '0x38CC0EDdD3a944CA17981e0A19470d2298B8d43a', - bootstrap: '0xCF2808eA7d131d96E5C73Eb0eCD8Dc84D33905C7', + bootstrap: '0x6e5E238F8cA164CDe6a8C88407FB242b05524658', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', - hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', + hookMultiPlexer: '0xA59DcC4495951D731F0d8e289b0ff1F5914f88EB', + credibleAccountModule: '0x0fdA37d4cbD43f63F962a1Fd1066F64D2e0dC3b0', + resourceLockValidator: '' }, }, [10]: { @@ -132,6 +134,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [137]: { @@ -146,6 +149,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [42161]: { @@ -160,6 +164,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [1]: { @@ -174,6 +179,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [10200]: { @@ -188,6 +194,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [122]: { @@ -202,6 +209,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [123]: { @@ -217,6 +225,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [100]: { @@ -231,6 +240,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [2357]: { @@ -245,6 +255,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [30]: { @@ -259,6 +270,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [31]: { @@ -273,6 +285,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [5000]: { @@ -287,6 +300,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [5003]: { @@ -301,6 +315,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [43114]: { @@ -315,6 +330,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [8453]: { @@ -329,6 +345,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [56]: { @@ -343,6 +360,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [97]: { @@ -357,6 +375,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [43113]: { @@ -371,6 +390,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [59144]: { @@ -385,6 +405,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [59140]: { @@ -399,6 +420,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [114]: { @@ -413,6 +435,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [14]: { @@ -427,6 +450,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [534351]: { @@ -441,6 +465,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [534352]: { @@ -455,6 +480,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [11155420]: { @@ -469,6 +495,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [28122024]: { @@ -483,6 +510,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [888888888]: { @@ -497,6 +525,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [80002]: { @@ -511,6 +540,7 @@ export const Networks: { erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [421614]: { @@ -525,6 +555,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [51]: { @@ -539,6 +570,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [50]: { @@ -553,6 +585,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [44787]: { @@ -567,6 +600,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [42220]: { @@ -581,6 +615,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, [79479957]: { @@ -608,6 +643,7 @@ export const Networks: { erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', credibleAccountModule: '', + resourceLockValidator: '' }, }, }; diff --git a/src/sdk/network/interfaces.ts b/src/sdk/network/interfaces.ts index 0791a89..3c116ef 100644 --- a/src/sdk/network/interfaces.ts +++ b/src/sdk/network/interfaces.ts @@ -18,5 +18,6 @@ export interface NetworkConfig { erc20SessionKeyValidator: string; hookMultiPlexer: string; credibleAccountModule: string; + resourceLockValidator: string; }; }; From bf042d2a4209b819eadae56953e653fd4aad9b6b Mon Sep 17 00:00:00 2001 From: kanth Date: Mon, 9 Jun 2025 11:59:30 +0530 Subject: [PATCH 10/22] feat: resourcelock-validator initiData generation for getInitCode function --- .../credible-account-ecosystem-install.ts | 112 ++++++++++++++++++ .../hook-multiplexer-has-hook.ts | 28 +++++ .../install-credible-account-module.ts | 44 +++++++ .../install-hook-multiplexer.ts | 44 +++++++ .../install-resource-lock-validator.ts | 43 +++++++ .../uninstall-credible-account-module.ts | 59 +++++++++ .../uninstall-hook-multiplexer.ts | 53 +++++++++ .../uninstall-resourcelock-validator.ts | 55 +++++++++ examples/pulse/utils.ts | 2 + src/sdk/base/EtherspotWalletAPI.ts | 32 ++++- src/sdk/network/constants.ts | 16 +-- src/sdk/sdk.ts | 4 + 12 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 examples/modules/credible-account-modules/credible-account-ecosystem-install.ts create mode 100644 examples/modules/credible-account-modules/hook-multiplexer-has-hook.ts create mode 100644 examples/modules/credible-account-modules/install-credible-account-module.ts create mode 100644 examples/modules/credible-account-modules/install-hook-multiplexer.ts create mode 100644 examples/modules/credible-account-modules/install-resource-lock-validator.ts create mode 100644 examples/modules/credible-account-modules/uninstall-credible-account-module.ts create mode 100644 examples/modules/credible-account-modules/uninstall-hook-multiplexer.ts create mode 100644 examples/modules/credible-account-modules/uninstall-resourcelock-validator.ts diff --git a/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts new file mode 100644 index 0000000..3a06e86 --- /dev/null +++ b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts @@ -0,0 +1,112 @@ +import { printOp } from '../../../src/sdk/common/OperationUtils'; +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { encodeAbiParameters, encodeFunctionData, Hex, parseAbi } from 'viem'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { getHookMultiPlexerInitData } from '../../pulse/utils'; +import { accountAbi } from '../../../src/sdk/common/abis'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +const bundlerApiKey = 'etherspot_public_key'; + +// tsx examples/modules/credible-account-modules/credible-account-ecosystem-install.ts +async function main() { + + const chainId = Number(process.env.CHAIN_ID); + + // Init SDK + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, + bundlerApiKey, + ); + + const networkConfig : NetworkConfig = Networks[chainId]; + + const HOOK_MULTIPLEXER_ADDRESS = networkConfig.contracts.hookMultiPlexer as Hex; + const RESOURCE_LOCK_VALIDATOR_ADDRESS = networkConfig.contracts.resourceLockValidator as Hex; + const CREDIBLE_ACCOUNT_MODULE_ADDRESS = networkConfig.contracts.credibleAccountModule as Hex; + + // Get counterfactual of ModularEtherspotWallet... + const address: Hex = (await modularSdk.getCounterFactualAddress()) as Hex; + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + // Get native balance + const balance = await modularSdk.getNativeBalance(); + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet native balance: ${balance}`); + // Clear existing UserOps from batch + await modularSdk.clearUserOpsFromBatch(); + + /*////////////////////////////////////////////////////////////// + INSTALL HOOK MULTIPLEXER WITH CREDIBLE ACCOUNT MODULE - AS HOOK + //////////////////////////////////////////////////////////////*/ + + //Get HookMultiPlexer init data with CredibleAccountHook as global subhook + let hmpInitData = getHookMultiPlexerInitData([CREDIBLE_ACCOUNT_MODULE_ADDRESS]); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> HmpInitData: ${hmpInitData}`); + const hmpInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, hmpInitData], + }); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> HmpInstallCalldata: ${hmpInstallCalldata}`); + // Add UserOp to batch + await modularSdk.addUserOpsToBatch({ to: address, data: hmpInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + INSTALL CREDIBLE ACCOUNT MODULE - AS VALIDATOR + //////////////////////////////////////////////////////////////*/ + + //Get CredibleAccountValidator init data + let cavInitData = encodeAbiParameters([{ type: 'uint256' }], [BigInt(MODULE_TYPE.VALIDATOR)]); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> CavInitData: ${cavInitData}`); + const cavInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.VALIDATOR), CREDIBLE_ACCOUNT_MODULE_ADDRESS, cavInitData], + }); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> cavInstallCalldata: ${cavInstallCalldata}`); + //Add UserOp to batch + //await modularSdk.addUserOpsToBatch({ to: address, data: cavInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + INSTALL RESOURCE LOCK VALIDATOR + //////////////////////////////////////////////////////////////*/ + + // Get ResourceLockValidator init data + let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> RlvInitData: ${rlvInitData}`); + const rlvInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.VALIDATOR), RESOURCE_LOCK_VALIDATOR_ADDRESS, rlvInitData], + }); + console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> RlvInstallCalldata: ${rlvInstallCalldata}`); + // Add UserOp to batch + await modularSdk.addUserOpsToBatch({ to: address, data: rlvInstallCalldata }); + + /*////////////////////////////////////////////////////////////// + ESTIMATE/SEND USER OP + //////////////////////////////////////////////////////////////*/ + + // Estimate UserOp + const op = await modularSdk.estimate(); + console.log(`Estimate UserOp: ${await printOp(op)}`); + // Send UserOp + const uoHash = await modularSdk.send(op); + console.log(`UserOpHash: ${uoHash}`); + // Await transaction hash + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 1200000; // 1 minute timeout + while (userOpsReceipt == null && Date.now() < timeout) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/hook-multiplexer-has-hook.ts b/examples/modules/credible-account-modules/hook-multiplexer-has-hook.ts new file mode 100644 index 0000000..daa47d0 --- /dev/null +++ b/examples/modules/credible-account-modules/hook-multiplexer-has-hook.ts @@ -0,0 +1,28 @@ +import { EtherspotBundler, ModularSdk } from '../../../src'; +import * as dotenv from 'dotenv'; +import { getViemAccount } from '../../../src/sdk/common/utils'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/hook-multiplexer-has-hook.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + Number(process.env.CHAIN_ID), bundlerApiKey); + + // get address of EtherspotWallet + const address: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + + const moduleInfo = await modularSdk.getAllModules(); + console.log(`moduleInfo: ${JSON.stringify(moduleInfo)}`); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/install-credible-account-module.ts b/examples/modules/credible-account-modules/install-credible-account-module.ts new file mode 100644 index 0000000..5a6a6e5 --- /dev/null +++ b/examples/modules/credible-account-modules/install-credible-account-module.ts @@ -0,0 +1,44 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/install-credible-account-module.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const address: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + + let cavInitData = encodeAbiParameters([{ type: 'uint256' }], [BigInt(MODULE_TYPE.VALIDATOR)]); + console.log('\x1b[33m%s\x1b[0m', `CavInitData: ${cavInitData}`); + + const networkConfig : NetworkConfig = Networks[chainId]; + const uoHash = await modularSdk.installModule(MODULE_TYPE.VALIDATOR, networkConfig.contracts.credibleAccountModule, cavInitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/install-hook-multiplexer.ts b/examples/modules/credible-account-modules/install-hook-multiplexer.ts new file mode 100644 index 0000000..d805c21 --- /dev/null +++ b/examples/modules/credible-account-modules/install-hook-multiplexer.ts @@ -0,0 +1,44 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters, Hex } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; +import { getHookMultiPlexerInitData } from '../../pulse/utils'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/install-hook-multiplexer.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const address: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + + const networkConfig : NetworkConfig = Networks[chainId]; + + let hmpInitData = getHookMultiPlexerInitData([networkConfig.contracts.credibleAccountModule as Hex]); + const uoHash = await modularSdk.installModule(MODULE_TYPE.HOOK, networkConfig.contracts.credibleAccountModule, hmpInitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/install-resource-lock-validator.ts b/examples/modules/credible-account-modules/install-resource-lock-validator.ts new file mode 100644 index 0000000..3956af7 --- /dev/null +++ b/examples/modules/credible-account-modules/install-resource-lock-validator.ts @@ -0,0 +1,43 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/install-resource-lock-validator.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const address: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); + + let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); + + const networkConfig : NetworkConfig = Networks[chainId]; + const uoHash = await modularSdk.installModule(MODULE_TYPE.VALIDATOR, networkConfig.contracts.resourceLockValidator, rlvInitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/uninstall-credible-account-module.ts b/examples/modules/credible-account-modules/uninstall-credible-account-module.ts new file mode 100644 index 0000000..c156458 --- /dev/null +++ b/examples/modules/credible-account-modules/uninstall-credible-account-module.ts @@ -0,0 +1,59 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters, Hex } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/uninstall-credible-account-module.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const etherspotWalletAddress: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${etherspotWalletAddress}`); + + const networkConfig : NetworkConfig = Networks[chainId]; + + //this should be previous node address of the module to be uninstalled and the deinit data + //deinit data is the data that is passed to the module to be uninstalled + // here we need to call the function which can find out the address of previous node of the module to be uninstalled + // and the deinit data can be 0x00 as default value + const deInitDataDefault = encodeAbiParameters([{ type: 'uint256' }, { type: 'address' }], + [BigInt(MODULE_TYPE.VALIDATOR), etherspotWalletAddress as Hex]); + + //generate deinit data... + const deInitData = await modularSdk.generateModuleDeInitData( + MODULE_TYPE.VALIDATOR, + networkConfig.contracts.credibleAccountModule, + deInitDataDefault); + + console.log(`deinitData: ${deInitData}`); + + const uoHash = await modularSdk.uninstallModule(MODULE_TYPE.VALIDATOR, + networkConfig.contracts.credibleAccountModule, deInitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/uninstall-hook-multiplexer.ts b/examples/modules/credible-account-modules/uninstall-hook-multiplexer.ts new file mode 100644 index 0000000..a5a8e24 --- /dev/null +++ b/examples/modules/credible-account-modules/uninstall-hook-multiplexer.ts @@ -0,0 +1,53 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters, Hex } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/uninstall-hook-multiplexer.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const etherspotWalletAddress: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${etherspotWalletAddress}`); + + const networkConfig : NetworkConfig = Networks[chainId]; + + //this should be previous node address of the module to be uninstalled and the deinit data + //deinit data is the data that is passed to the module to be uninstalled + // here we need to call the function which can find out the address of previous node of the module to be uninstalled + // and the deinit data can be 0x00 as default value + const deinitData = encodeAbiParameters([{ type: 'uint256' }], + [BigInt(MODULE_TYPE.HOOK)]); + + console.log(`deinitData: ${deinitData}`); + + const uoHash = await modularSdk.uninstallModule(MODULE_TYPE.HOOK, + networkConfig.contracts.hookMultiPlexer, deinitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/modules/credible-account-modules/uninstall-resourcelock-validator.ts b/examples/modules/credible-account-modules/uninstall-resourcelock-validator.ts new file mode 100644 index 0000000..569904c --- /dev/null +++ b/examples/modules/credible-account-modules/uninstall-resourcelock-validator.ts @@ -0,0 +1,55 @@ +import * as dotenv from 'dotenv'; +import { MODULE_TYPE, sleep } from '../../../src/sdk/common'; +import { generateModularSDKInstance } from '../../helpers/sdk-helper'; +import { encodeAbiParameters, Hex } from 'viem'; +import { NetworkConfig, Networks } from '../../../src'; + +dotenv.config(); + +// tsx examples/modules/credible-account-modules/uninstall-resourcelock-validator.ts +async function main() { + const bundlerApiKey = 'etherspot_public_key'; + + const chainId = Number(process.env.CHAIN_ID); + + // initializating sdk... + const modularSdk = generateModularSDKInstance( + process.env.WALLET_PRIVATE_KEY as string, + chainId, bundlerApiKey); + + // get address of EtherspotWallet + const etherspotWalletAddress: string = await modularSdk.getCounterFactualAddress(); + + console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${etherspotWalletAddress}`); + + const networkConfig : NetworkConfig = Networks[chainId]; + + //this should be previous node address of the module to be uninstalled and the deinit data + //deinit data is the data that is passed to the module to be uninstalled + // here we need to call the function which can find out the address of previous node of the module to be uninstalled + // and the deinit data can be 0x00 as default value + const deInitDataDefault = '0x00'; + //generate deinit data... + const deInitData = await modularSdk.generateModuleDeInitData( + MODULE_TYPE.VALIDATOR, + networkConfig.contracts.resourceLockValidator, + deInitDataDefault); + + const uoHash = await modularSdk.uninstallModule(MODULE_TYPE.VALIDATOR, + networkConfig.contracts.resourceLockValidator, deInitData); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/pulse/utils.ts b/examples/pulse/utils.ts index 13c9ae7..9946b6d 100644 --- a/examples/pulse/utils.ts +++ b/examples/pulse/utils.ts @@ -46,5 +46,7 @@ export function getHookMultiPlexerInitData( sigHooks, targetSigHooks ]); + + console.log('\x1b[33m%s\x1b[0m', `HookMultiPlexer Init Data: ${encodedData}`); return encodedData; } \ No newline at end of file diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 4675428..237d129 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -244,7 +244,7 @@ export class EtherspotWalletAPI extends BaseAccountAPI { [ this.validatorAddress, this.credibleAccountModuleAddress as Hex, - this.resourceLockValidatorAddress + this.resourceLockValidatorAddress as Hex ] , [ '0x', @@ -252,16 +252,14 @@ export class EtherspotWalletAPI extends BaseAccountAPI { parseAbiParameters('uint256'), [BigInt(MODULE_TYPE.VALIDATOR)] ), - '0x' + encodeAbiParameters([{ type: 'address' }], [this.services.walletService.EOAAddress as Hex]), ] ); const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); //Get HookMultiPlexer init data with CredibleAccountHook as global subhook - let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData( - [this.credibleAccountModuleAddress as Hex] - ); + let hmpInitData = this.credibleAccountModuleAddress == ADDRESS_ZERO ? '0x' : getHookMultiPlexerInitData([this.credibleAccountModuleAddress as Hex]); const hook: BootstrapConfig = _makeBootstrapConfig(this.hookMultiplexerAddress as Hex, hmpInitData); const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); @@ -281,6 +279,30 @@ export class EtherspotWalletAPI extends BaseAccountAPI { return initCode; } + // async getInitCodeData(): Promise { + // if (!this.validatorAddress) { + // throw new Error('Validator address not found'); + // } + // const validators: BootstrapConfig[] = makeBootstrapConfig(this.validatorAddress, '0x'); + // const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); + // const hook: BootstrapConfig = _makeBootstrapConfig(ADDRESS_ZERO, '0x'); + // const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); + + // const initMSAData = encodeFunctionData({ + // functionName: 'initMSA', + // abi: parseAbi(bootstrapAbi), + // args: [validators, executors, hook, fallbacks], + // }); + // const eoaAddress = await this.getEOAAddress(); + + // const initCode = encodeAbiParameters( + // parseAbiParameters('address, address, bytes'), + // [eoaAddress, this.bootstrapAddress as Hex, initMSAData] + // ) + + // return initCode; + // } + /** * return the value to put into the "initCode" field, if the account is not yet deployed. * this value holds the "factory" address, followed by this account's information diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index b9d6252..eb820b7 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -98,12 +98,12 @@ export const Networks: { contracts: { entryPoint: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', walletFactory: '0x38CC0EDdD3a944CA17981e0A19470d2298B8d43a', - bootstrap: '0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C', + bootstrap: '0x2229B2C3D00a213D93151cd65C31e5b4ea4D0330', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', - hookMultiPlexer: '0xB56335BaEB331DF3955ac4d6841ac6DdA5b14cb4', - credibleAccountModule: '0xF34fEBDCc36D7246498C56bEfc10bE5dC694C494', - resourceLockValidator: "0x9569FaD05892164ca3daf9a90f0590543eC97A7d", + hookMultiPlexer: '0x78E8aEb28C7730c27a7B5df4380aa9963A3d3423', + credibleAccountModule: '0xe3b2eC604AC5a8B76EaB74F107CE32CE48364624', + resourceLockValidator: "0x9AD563258C9d007E9F6F372D11a50b5D4DB553E4", }, }, [11155111]: { @@ -113,12 +113,12 @@ export const Networks: { contracts: { entryPoint: '0x0000000071727De22E5E9d8BAf0edAc6f37da032', walletFactory: '0x38CC0EDdD3a944CA17981e0A19470d2298B8d43a', - bootstrap: '0x6e5E238F8cA164CDe6a8C88407FB242b05524658', + bootstrap: '0xFD109F06162B76d6A7752B853F4e825Df2cC9cBA', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', - hookMultiPlexer: '0xA59DcC4495951D731F0d8e289b0ff1F5914f88EB', - credibleAccountModule: '0x0fdA37d4cbD43f63F962a1Fd1066F64D2e0dC3b0', - resourceLockValidator: '' + hookMultiPlexer: '0x018c9824f25c5Ba653da88aD1cCC7355698f9186', + credibleAccountModule: '0x97c4954752BDA1826ff66f7BF044cFA512e3ca83', + resourceLockValidator: '0x7B2852637D62c4DAfc146e3bA4EE81dFD817Ff13' }, }, [10]: { diff --git a/src/sdk/sdk.ts b/src/sdk/sdk.ts index 159a01a..acb1445 100644 --- a/src/sdk/sdk.ts +++ b/src/sdk/sdk.ts @@ -21,6 +21,7 @@ import { ErrorHandler } from './errorHandler/errorHandler.service.js'; import { EtherspotBundler } from './bundler/index.js'; import { Account, formatEther, Hex, http, type PublicClient } from 'viem'; import { BigNumber, BigNumberish } from './types/bignumber.js'; +import { printOp } from './common/OperationUtils.js'; /** * Modular-Sdk @@ -209,6 +210,9 @@ export class ModularSdk { partialtx.factory = this.etherspotWallet.factoryAddress; } + console.log('Partial User Operation:', partialtx); + console.log(`User Operation: ${await printOp(partialtx)}`); + if (!paymasterDetails?.url) { const bundlerGasEstimate = await this.bundler.getVerificationGasInfo(partialtx); From 389fe3366ed20c727b3287f3ad8046e26485f73b Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Tue, 10 Jun 2025 18:30:46 +0530 Subject: [PATCH 11/22] module install script changes --- .../credible-account-ecosystem-install.ts | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/examples/modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-ecosystem-install.ts index d84e2a4..1b188db 100644 --- a/examples/modules/credible-account-ecosystem-install.ts +++ b/examples/modules/credible-account-ecosystem-install.ts @@ -3,8 +3,9 @@ import * as dotenv from 'dotenv'; import { MODULE_TYPE, sleep } from '../../src/sdk/common'; import { encodeAbiParameters, encodeFunctionData, Hex, parseAbi } from 'viem'; import { generateModularSDKInstance } from '../helpers/sdk-helper'; -import { getHookMultiPlexerInitData } from '../pulse/utils'; import { accountAbi } from '../../src/sdk/common/abis'; +import { getHookMultiPlexerInitData } from '../../src/sdk/common/getInitData'; +import { _makeBootstrapConfig } from '../../src/sdk/base/Bootstrap'; dotenv.config(); @@ -20,10 +21,10 @@ const bundlerApiKey = 'etherspot_public_key'; // const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0x56BE864234F5710C00868e29e1fbB76ad4f234e3'; // const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0xFa970f9Bd071999FD54F7fDD80cA17965Fa8f5b6'; -const CHAIN_ID = '8453'; -const HOOK_MULTIPLEXER_ADDRESS = '0xDcA918dd23456d321282DF9507F6C09A50522136'; -const RESOURCE_LOCK_VALIDATOR_ADDRESS = ''; -const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0xDcA918dd23456d321282DF9507F6C09A50522136'; +const CHAIN_ID = '11155111'; +const HOOK_MULTIPLEXER_ADDRESS = '0x018c9824f25c5Ba653da88aD1cCC7355698f9186'; +const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0x7B2852637D62c4DAfc146e3bA4EE81dFD817Ff13'; +const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0x97c4954752BDA1826ff66f7BF044cFA512e3ca83'; // const CHAIN_ID = '10'; // const HOOK_MULTIPLEXER_ADDRESS = ''; @@ -54,12 +55,13 @@ async function main() { //Get HookMultiPlexer init data with CredibleAccountHook as global subhook let hmpInitData = getHookMultiPlexerInitData([CREDIBLE_ACCOUNT_MODULE_ADDRESS]); + const config = _makeBootstrapConfig(HOOK_MULTIPLEXER_ADDRESS, hmpInitData); const hmpInstallCalldata = encodeFunctionData({ abi: parseAbi(accountAbi), functionName: 'installModule', - args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, hmpInitData], + args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, config.data], }); - // // Add UserOp to batch + // Add UserOp to batch await modularSdk.addUserOpsToBatch({ to: address, data: hmpInstallCalldata }); /*////////////////////////////////////////////////////////////// @@ -81,14 +83,14 @@ async function main() { //////////////////////////////////////////////////////////////*/ // Get CredibleAccountValidator init data - // let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); - // const rlvInstallCalldata = encodeFunctionData({ - // abi: parseAbi(accountAbi), - // functionName: 'installModule', - // args: [BigInt(MODULE_TYPE.VALIDATOR), RESOURCE_LOCK_VALIDATOR_ADDRESS, rlvInitData], - // }); - // // Add UserOp to batch - // await modularSdk.addUserOpsToBatch({ to: address, data: rlvInstallCalldata }); + let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); + const rlvInstallCalldata = encodeFunctionData({ + abi: parseAbi(accountAbi), + functionName: 'installModule', + args: [BigInt(MODULE_TYPE.VALIDATOR), RESOURCE_LOCK_VALIDATOR_ADDRESS, rlvInitData], + }); + // Add UserOp to batch + await modularSdk.addUserOpsToBatch({ to: address, data: rlvInstallCalldata }); /*////////////////////////////////////////////////////////////// ESTIMATE/SEND USER OP From 326c43b73fb150fdfa0e4767473c075b7eaf2b40 Mon Sep 17 00:00:00 2001 From: kanth Date: Thu, 12 Jun 2025 10:38:31 +0530 Subject: [PATCH 12/22] feat: remove redundant initCode function --- src/sdk/base/EtherspotWalletAPI.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/sdk/base/EtherspotWalletAPI.ts b/src/sdk/base/EtherspotWalletAPI.ts index 237d129..762c878 100644 --- a/src/sdk/base/EtherspotWalletAPI.ts +++ b/src/sdk/base/EtherspotWalletAPI.ts @@ -279,30 +279,6 @@ export class EtherspotWalletAPI extends BaseAccountAPI { return initCode; } - // async getInitCodeData(): Promise { - // if (!this.validatorAddress) { - // throw new Error('Validator address not found'); - // } - // const validators: BootstrapConfig[] = makeBootstrapConfig(this.validatorAddress, '0x'); - // const executors: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); - // const hook: BootstrapConfig = _makeBootstrapConfig(ADDRESS_ZERO, '0x'); - // const fallbacks: BootstrapConfig[] = makeBootstrapConfig(ADDRESS_ZERO, '0x'); - - // const initMSAData = encodeFunctionData({ - // functionName: 'initMSA', - // abi: parseAbi(bootstrapAbi), - // args: [validators, executors, hook, fallbacks], - // }); - // const eoaAddress = await this.getEOAAddress(); - - // const initCode = encodeAbiParameters( - // parseAbiParameters('address, address, bytes'), - // [eoaAddress, this.bootstrapAddress as Hex, initMSAData] - // ) - - // return initCode; - // } - /** * return the value to put into the "initCode" field, if the account is not yet deployed. * this value holds the "factory" address, followed by this account's information From cc5ad458fb69f764c9edf87c571e0109577e9c8a Mon Sep 17 00:00:00 2001 From: kanth Date: Wed, 18 Jun 2025 17:05:40 +0530 Subject: [PATCH 13/22] fix: correct and set the HMP, RAL addresses for sepolia and basesepolia --- src/sdk/network/constants.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index eb820b7..1cffbc7 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -101,9 +101,9 @@ export const Networks: { bootstrap: '0x2229B2C3D00a213D93151cd65C31e5b4ea4D0330', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', - hookMultiPlexer: '0x78E8aEb28C7730c27a7B5df4380aa9963A3d3423', - credibleAccountModule: '0xe3b2eC604AC5a8B76EaB74F107CE32CE48364624', - resourceLockValidator: "0x9AD563258C9d007E9F6F372D11a50b5D4DB553E4", + hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '0xfd090eAFdb3dccE1FA9517ce52BaeBAd1d8cE939', + resourceLockValidator: "0xa3789284adB928258DA2cC674090AC5c69D22183", }, }, [11155111]: { @@ -116,9 +116,9 @@ export const Networks: { bootstrap: '0xFD109F06162B76d6A7752B853F4e825Df2cC9cBA', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', - hookMultiPlexer: '0x018c9824f25c5Ba653da88aD1cCC7355698f9186', - credibleAccountModule: '0x97c4954752BDA1826ff66f7BF044cFA512e3ca83', - resourceLockValidator: '0x7B2852637D62c4DAfc146e3bA4EE81dFD817Ff13' + hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', + credibleAccountModule: '0xfd090eAFdb3dccE1FA9517ce52BaeBAd1d8cE939', + resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' }, }, [10]: { From 126302bff6ea5d9fa6d2bb2e0334dfc7913efe73 Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Wed, 18 Jun 2025 23:57:14 +0530 Subject: [PATCH 14/22] update: CAM and RLV addresses for polygon, arb, op and base --- src/sdk/network/constants.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 1cffbc7..3aaf20d 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -133,8 +133,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xddFAE48a3219b3037dDBd5ee108a283F2d4DBDcd', + resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' }, }, [137]: { @@ -148,8 +148,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xddFAE48a3219b3037dDBd5ee108a283F2d4DBDcd', + resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' }, }, [42161]: { @@ -163,8 +163,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xddFAE48a3219b3037dDBd5ee108a283F2d4DBDcd', + resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' }, }, [1]: { @@ -344,8 +344,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xddFAE48a3219b3037dDBd5ee108a283F2d4DBDcd', + resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' }, }, [56]: { From 3a615d6715975a040ee5e856be434c5cad870bec Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Wed, 25 Jun 2025 17:34:10 +0530 Subject: [PATCH 15/22] updating CAM, RLV addresses for gnosis and bsc --- src/sdk/network/constants.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 3aaf20d..31f70ab 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -239,8 +239,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xb8970dB5cd5617411577a8eCE93b16CCf244e7A4', + resourceLockValidator: '0x7948Ad29e179716793B3F404F91a9d8aa0275712' }, }, [2357]: { @@ -359,8 +359,8 @@ export const Networks: { multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '', hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '', - resourceLockValidator: '' + credibleAccountModule: '0xb8970dB5cd5617411577a8eCE93b16CCf244e7A4', + resourceLockValidator: '0x7948Ad29e179716793B3F404F91a9d8aa0275712' }, }, [97]: { From 037590a6c94d0a0e8b8bd7a1eb85a737f94d1e2e Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Wed, 25 Jun 2025 19:57:54 +0530 Subject: [PATCH 16/22] fix for install modules --- .../credible-account-ecosystem-install.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts index 3a06e86..4ff957a 100644 --- a/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts +++ b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts @@ -6,6 +6,7 @@ import { generateModularSDKInstance } from '../../helpers/sdk-helper'; import { getHookMultiPlexerInitData } from '../../pulse/utils'; import { accountAbi } from '../../../src/sdk/common/abis'; import { NetworkConfig, Networks } from '../../../src'; +import { _makeBootstrapConfig } from '../../../src/sdk/base/Bootstrap'; dotenv.config(); @@ -44,11 +45,12 @@ async function main() { //Get HookMultiPlexer init data with CredibleAccountHook as global subhook let hmpInitData = getHookMultiPlexerInitData([CREDIBLE_ACCOUNT_MODULE_ADDRESS]); + const config = _makeBootstrapConfig(HOOK_MULTIPLEXER_ADDRESS, hmpInitData); console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> HmpInitData: ${hmpInitData}`); const hmpInstallCalldata = encodeFunctionData({ abi: parseAbi(accountAbi), functionName: 'installModule', - args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, hmpInitData], + args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, config.data], }); console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> HmpInstallCalldata: ${hmpInstallCalldata}`); // Add UserOp to batch @@ -68,7 +70,7 @@ async function main() { }); console.log('\x1b[33m%s\x1b[0m', `Credible-Setup -> cavInstallCalldata: ${cavInstallCalldata}`); //Add UserOp to batch - //await modularSdk.addUserOpsToBatch({ to: address, data: cavInstallCalldata }); + await modularSdk.addUserOpsToBatch({ to: address, data: cavInstallCalldata }); /*////////////////////////////////////////////////////////////// INSTALL RESOURCE LOCK VALIDATOR From 8ea84be9d32012a08846325db82063b65b15d380 Mon Sep 17 00:00:00 2001 From: nikhil kumar Date: Thu, 26 Jun 2025 17:12:22 +0530 Subject: [PATCH 17/22] minor changes for sdk instance creation and move api key to env --- examples/helpers/sdk-helper.ts | 3 ++- .../credible-account-ecosystem-install.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/helpers/sdk-helper.ts b/examples/helpers/sdk-helper.ts index a019e4c..2bbbaf3 100644 --- a/examples/helpers/sdk-helper.ts +++ b/examples/helpers/sdk-helper.ts @@ -9,7 +9,8 @@ export const generateModularSDKInstance = (privateKey: string, chainId: number, { chainId: chainId, bundlerProvider: new EtherspotBundler(chainId, bundlerApiKey), - index: index + index: index, + accountAddress: process.env.MODULAR_ACCOUNT_ADDRESS }) return modularSdk; diff --git a/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts index 4ff957a..db8c773 100644 --- a/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts +++ b/examples/modules/credible-account-modules/credible-account-ecosystem-install.ts @@ -10,7 +10,7 @@ import { _makeBootstrapConfig } from '../../../src/sdk/base/Bootstrap'; dotenv.config(); -const bundlerApiKey = 'etherspot_public_key'; +const bundlerApiKey = process.env.API_KEY || "etherspot_public_key"; // tsx examples/modules/credible-account-modules/credible-account-ecosystem-install.ts async function main() { From 70511d5c9ae19cdec584397f265833569ed9ccbd Mon Sep 17 00:00:00 2001 From: kanth Date: Fri, 27 Jun 2025 17:24:42 +0530 Subject: [PATCH 18/22] feat: resource-lock script to claim locked funds --- .../credible-account-ecosystem-install.ts | 118 ------------------ .../claim-resourcelock-session-key.ts | 89 +++++++++++++ .../resource-lock/get-session-key-pair.ts | 35 ++++++ 3 files changed, 124 insertions(+), 118 deletions(-) delete mode 100644 examples/modules/credible-account-ecosystem-install.ts create mode 100644 examples/resource-lock/claim-resourcelock-session-key.ts create mode 100644 examples/resource-lock/get-session-key-pair.ts diff --git a/examples/modules/credible-account-ecosystem-install.ts b/examples/modules/credible-account-ecosystem-install.ts deleted file mode 100644 index 1b188db..0000000 --- a/examples/modules/credible-account-ecosystem-install.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { printOp } from '../../src/sdk/common/OperationUtils'; -import * as dotenv from 'dotenv'; -import { MODULE_TYPE, sleep } from '../../src/sdk/common'; -import { encodeAbiParameters, encodeFunctionData, Hex, parseAbi } from 'viem'; -import { generateModularSDKInstance } from '../helpers/sdk-helper'; -import { accountAbi } from '../../src/sdk/common/abis'; -import { getHookMultiPlexerInitData } from '../../src/sdk/common/getInitData'; -import { _makeBootstrapConfig } from '../../src/sdk/base/Bootstrap'; - -dotenv.config(); - -const bundlerApiKey = 'etherspot_public_key'; -// const CHAIN_ID = '84532'; -// const HOOK_MULTIPLEXER_ADDRESS = '0x61c58064640C752e950647c8AFDf1E2C0a098251'; -// const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0x373aBcF1EA9e5802778E32870e7f72C8A6a90349'; -// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0xbb4D635B26a565B3722B4683459A27D3747101Ab'; - - -// const CHAIN_ID = '11155111'; -// const HOOK_MULTIPLEXER_ADDRESS = '0x0d1F23CA4092eBF61291622616a73008d5d7e9FF'; -// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0x56BE864234F5710C00868e29e1fbB76ad4f234e3'; -// const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0xFa970f9Bd071999FD54F7fDD80cA17965Fa8f5b6'; - -const CHAIN_ID = '11155111'; -const HOOK_MULTIPLEXER_ADDRESS = '0x018c9824f25c5Ba653da88aD1cCC7355698f9186'; -const RESOURCE_LOCK_VALIDATOR_ADDRESS = '0x7B2852637D62c4DAfc146e3bA4EE81dFD817Ff13'; -const CREDIBLE_ACCOUNT_MODULE_ADDRESS = '0x97c4954752BDA1826ff66f7BF044cFA512e3ca83'; - -// const CHAIN_ID = '10'; -// const HOOK_MULTIPLEXER_ADDRESS = ''; -// const CREDIBLE_ACCOUNT_MODULE_ADDRESS = ''; -// const RESOURCE_LOCK_VALIDATOR_ADDRESS = ''; - -// tsx examples/modules/credible-account-ecosystem-install.ts -async function main() { - // Init SDK - const modularSdk = generateModularSDKInstance( - process.env.WALLET_PRIVATE_KEY as string, - Number(CHAIN_ID), - bundlerApiKey, - ); - - // Get counterfactual of ModularEtherspotWallet... - const address: Hex = (await modularSdk.getCounterFactualAddress()) as Hex; - console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet address: ${address}`); - // Get native balance - const balance = await modularSdk.getNativeBalance(); - console.log('\x1b[33m%s\x1b[0m', `EtherspotWallet native balance: ${balance}`); - // Clear existing UserOps from batch - await modularSdk.clearUserOpsFromBatch(); - - /*////////////////////////////////////////////////////////////// - INSTALL HOOK MULTIPLEXER WITH CREDIBLE ACCOUNT MODULE - AS HOOK - //////////////////////////////////////////////////////////////*/ - - //Get HookMultiPlexer init data with CredibleAccountHook as global subhook - let hmpInitData = getHookMultiPlexerInitData([CREDIBLE_ACCOUNT_MODULE_ADDRESS]); - const config = _makeBootstrapConfig(HOOK_MULTIPLEXER_ADDRESS, hmpInitData); - const hmpInstallCalldata = encodeFunctionData({ - abi: parseAbi(accountAbi), - functionName: 'installModule', - args: [BigInt(MODULE_TYPE.HOOK), HOOK_MULTIPLEXER_ADDRESS, config.data], - }); - // Add UserOp to batch - await modularSdk.addUserOpsToBatch({ to: address, data: hmpInstallCalldata }); - - /*////////////////////////////////////////////////////////////// - INSTALL CREDIBLE ACCOUNT MODULE - AS VALIDATOR - //////////////////////////////////////////////////////////////*/ - - //Get CredibleAccountValidator init data - let cavInitData = encodeAbiParameters([{ type: 'uint256' }], [BigInt(MODULE_TYPE.VALIDATOR)]); - const cavInstallCalldata = encodeFunctionData({ - abi: parseAbi(accountAbi), - functionName: 'installModule', - args: [BigInt(MODULE_TYPE.VALIDATOR), CREDIBLE_ACCOUNT_MODULE_ADDRESS, cavInitData], - }); - // Add UserOp to batch - await modularSdk.addUserOpsToBatch({ to: address, data: cavInstallCalldata }); - - /*////////////////////////////////////////////////////////////// - INSTALL RESOURCE LOCK VALIDATOR - //////////////////////////////////////////////////////////////*/ - - // Get CredibleAccountValidator init data - let rlvInitData = encodeAbiParameters([{ type: 'address' }], [modularSdk.getEOAAddress()]); - const rlvInstallCalldata = encodeFunctionData({ - abi: parseAbi(accountAbi), - functionName: 'installModule', - args: [BigInt(MODULE_TYPE.VALIDATOR), RESOURCE_LOCK_VALIDATOR_ADDRESS, rlvInitData], - }); - // Add UserOp to batch - await modularSdk.addUserOpsToBatch({ to: address, data: rlvInstallCalldata }); - - /*////////////////////////////////////////////////////////////// - ESTIMATE/SEND USER OP - //////////////////////////////////////////////////////////////*/ - - // Estimate UserOp - const op = await modularSdk.estimate(); - console.log(`Estimate UserOp: ${await printOp(op)}`); - // Send UserOp - const uoHash = await modularSdk.send(op); - console.log(`UserOpHash: ${uoHash}`); - // Await transaction hash - console.log('Waiting for transaction...'); - let userOpsReceipt = null; - const timeout = Date.now() + 1200000; // 1 minute timeout - while (userOpsReceipt == null && Date.now() < timeout) { - await sleep(2); - userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); - } - console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); -} - -main() - .catch(console.error) - .finally(() => process.exit()); diff --git a/examples/resource-lock/claim-resourcelock-session-key.ts b/examples/resource-lock/claim-resourcelock-session-key.ts new file mode 100644 index 0000000..5943e76 --- /dev/null +++ b/examples/resource-lock/claim-resourcelock-session-key.ts @@ -0,0 +1,89 @@ +import { BigNumber, ethers } from 'ethers'; +import * as dotenv from 'dotenv'; +import { printOp } from '../../src/sdk/common/OperationUtils'; +import { getViemAccount, sleep } from '../../src/sdk/common'; +import { ModularSdk, EtherspotBundler, Networks } from '../../src'; +import { ERC20_ABI } from '../../src/sdk/helpers/abi/ERC20_ABI'; +import { encodeFunctionData, Hex, parseAbi, parseUnits } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +dotenv.config(); + +const chainId = 10; +const walletPrivateKey = process.env.WALLET_PRIVATE_KEY as string; +const bundlerApiKey = 'etherspot_public_key'; +const user_modular_wallet_address = ''; + +const solverAddress = ''; +const tokenAmount = ''; +const tokenAddress = ""; +const sessionKeyAddress = ""; +const sessionPrivateKey = ''; + +// tsx examples/resource-lock/claim-resourcelock-session-key.ts +async function main() { + const modularSdk = new ModularSdk( + walletPrivateKey, + { + chainId: chainId, + bundlerProvider: new EtherspotBundler(chainId, bundlerApiKey), + index: 0, + accountAddress: user_modular_wallet_address + }) + + // get transferFrom encoded data + const transactionData = encodeFunctionData({ + functionName: 'transfer', + abi: parseAbi(ERC20_ABI), + args: [solverAddress, tokenAmount] + }); + + // clear the transaction batch + await modularSdk.clearUserOpsFromBatch(); + + // add transactions to the batch + const userOpsBatch = await modularSdk.addUserOpsToBatch({ to: tokenAddress, data: transactionData }); + console.log('transactions: ', userOpsBatch); + + const credibleAccountModuleAddress = Networks[chainId].contracts.credibleAccountModule; + + console.log(`credibleAccountModuleAddress ${credibleAccountModuleAddress} as BigNumber is: ${BigNumber.from(credibleAccountModuleAddress)}`); + + // estimate transactions added to the batch and get the fee data for the UserOp + const op = await modularSdk.estimate({ + key: BigNumber.from(credibleAccountModuleAddress) + }); + + const nonceBig = BigNumber.from(op.nonce); + console.log(`Nonce: ${nonceBig}`); + + console.log(`Estimate UserOp: ${await printOp(op)}`); + + const userOpHash : string = await modularSdk.getUserOpHash(op); + console.log(`UserOpHash: ${userOpHash}`); + + // sign the UserOp using sessionPrivateKey (with viem) + const sessionAccount = privateKeyToAccount(sessionPrivateKey as Hex); + const signature = await sessionAccount.signMessage({ message: { raw: userOpHash as Hex } }); + + // set the signedUserOpHash in the UserOp + op.signature = signature; + + // sending to the bundler with isUserOpAlreadySigned true... + const uoHash = await modularSdk.send(op, true); + console.log(`UserOpHash: ${uoHash}`); + + // get transaction hash... + console.log('Waiting for transaction...'); + let userOpsReceipt = null; + const timeout = Date.now() + 60000; // 1 minute timeout + while ((userOpsReceipt == null) && (Date.now() < timeout)) { + await sleep(2); + userOpsReceipt = await modularSdk.getUserOpReceipt(uoHash); + } + console.log('\x1b[33m%s\x1b[0m', `Transaction Receipt: `, userOpsReceipt); +} + +main() + .catch(console.error) + .finally(() => process.exit()); diff --git a/examples/resource-lock/get-session-key-pair.ts b/examples/resource-lock/get-session-key-pair.ts new file mode 100644 index 0000000..2601991 --- /dev/null +++ b/examples/resource-lock/get-session-key-pair.ts @@ -0,0 +1,35 @@ +import * as dotenv from 'dotenv'; +dotenv.config(); + +import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager"; + +const client = new SecretsManagerClient({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID!, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!, + } +}); + +async function getSecretFromBidHashAndSessionKey(bidHash: string, sessionKey: string) { + const secretName = `${sessionKey}-${bidHash}`; + console.log(`Fetching secret for: ${secretName}`); + if (!secretName) { + throw new Error("Secret name is required"); + } + const command = new GetSecretValueCommand({ SecretId: secretName }); + const response = await client.send(command); + if (response.SecretString) { + console.log(`Secret found for: ${secretName} as: ${response.SecretString}`); + return `0x${response.SecretString}`; + } + throw new Error("Secret not found"); +} + +// tsx examples/secrets-manager/get-session-key-pair.ts +(async () => { + const bidHash = '0x7931e1aca917a4673d583cdc599bcfe6ff19496922aa75a11499e726884b9aec'; + const sessionKey = '0xd0Df09FD15E6a4b2940A22a684EEC2F377E36a8C'; + const secret = await getSecretFromBidHashAndSessionKey(bidHash, sessionKey); + console.log(secret); +})(); \ No newline at end of file From 5794cc91b98fc7de67f0fdaccd562ecd05078222 Mon Sep 17 00:00:00 2001 From: kanth Date: Fri, 27 Jun 2025 17:59:21 +0530 Subject: [PATCH 19/22] feat: helper and executable script for claim-resource-lock --- .../claim-resourcelock-session-key.ts | 40 ++++++++++-- .../resource-lock/get-resourcelock-info.ts | 50 ++++++++++++++ .../resource-lock/get-session-key-details.ts | 54 +++++++++++++++ .../resource-lock/get-session-key-pair.ts | 2 +- examples/resource-lock/search-bid.ts | 65 +++++++++++++++++++ package.json | 5 +- 6 files changed, 206 insertions(+), 10 deletions(-) create mode 100644 examples/resource-lock/get-resourcelock-info.ts create mode 100644 examples/resource-lock/get-session-key-details.ts create mode 100644 examples/resource-lock/search-bid.ts diff --git a/examples/resource-lock/claim-resourcelock-session-key.ts b/examples/resource-lock/claim-resourcelock-session-key.ts index 5943e76..de565a9 100644 --- a/examples/resource-lock/claim-resourcelock-session-key.ts +++ b/examples/resource-lock/claim-resourcelock-session-key.ts @@ -6,6 +6,10 @@ import { ModularSdk, EtherspotBundler, Networks } from '../../src'; import { ERC20_ABI } from '../../src/sdk/helpers/abi/ERC20_ABI'; import { encodeFunctionData, Hex, parseAbi, parseUnits } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; +import { getSecretFromBidHashAndSessionKey } from './get-session-key-pair'; +import { getSessionDetailsByWalletAddressAndSessionKey, SessionDetails } from './get-session-key-details'; +import { BidSearchResult, searchBid } from './search-bid'; +import { getResourceLockInfo, ResourceLockInfoResponse } from './get-resourcelock-info'; dotenv.config(); @@ -14,14 +18,36 @@ const walletPrivateKey = process.env.WALLET_PRIVATE_KEY as string; const bundlerApiKey = 'etherspot_public_key'; const user_modular_wallet_address = ''; -const solverAddress = ''; -const tokenAmount = ''; -const tokenAddress = ""; -const sessionKeyAddress = ""; -const sessionPrivateKey = ''; +const bidHash = ''; // tsx examples/resource-lock/claim-resourcelock-session-key.ts async function main() { + + // search bid and get solver address + const bidSearchResult: BidSearchResult[] = await searchBid(bidHash); + + const bidDetails = bidSearchResult[0]; + + const solverAddress = bidDetails.solverAddress; + + const resourceLockInfoResponse: ResourceLockInfoResponse = await getResourceLockInfo(bidHash); + + const sessionKeyAddress = resourceLockInfoResponse.resourceLockInfo.sessionKey; + + // get session key private key from AWS Secrets Manager + const sessionPrivateKey = await getSecretFromBidHashAndSessionKey(solverAddress, sessionKeyAddress); + + // get the session-details from api-call + const sessionKeyDetails: SessionDetails = await getSessionDetailsByWalletAddressAndSessionKey( + chainId, + user_modular_wallet_address, + sessionKeyAddress + ); + + const tokenAddress = sessionKeyDetails.lockedTokens[0].token; + const tokenAmount = sessionKeyDetails.lockedTokens[0].locked_amount; + + // prepare UserOp to transfer the locked ERC20 tokens from the user's ModularWallet to the solver address const modularSdk = new ModularSdk( walletPrivateKey, { @@ -59,9 +85,9 @@ async function main() { console.log(`Estimate UserOp: ${await printOp(op)}`); - const userOpHash : string = await modularSdk.getUserOpHash(op); + const userOpHash: string = await modularSdk.getUserOpHash(op); console.log(`UserOpHash: ${userOpHash}`); - + // sign the UserOp using sessionPrivateKey (with viem) const sessionAccount = privateKeyToAccount(sessionPrivateKey as Hex); const signature = await sessionAccount.signMessage({ message: { raw: userOpHash as Hex } }); diff --git a/examples/resource-lock/get-resourcelock-info.ts b/examples/resource-lock/get-resourcelock-info.ts new file mode 100644 index 0000000..7553f6d --- /dev/null +++ b/examples/resource-lock/get-resourcelock-info.ts @@ -0,0 +1,50 @@ +import axios from 'axios'; + +export interface TokenData { + token: string; + amount: number; +} + +export interface ResourceLock { + chainId: number; + tokenData: TokenData[]; + proof: string[]; + userOpHash: string; + transactionHash: string; +} + +export interface ResourceLockInfo { + intentHash: string; + bidHash: string; + rootHash: string; + smartWallet: string; + sessionKey: string; + validAfter: number; + validUntil: number; + resourceLocks: ResourceLock[]; + signature: string; + account: string; +} + +export interface ResourceLockInfoResponse { + intentHash: string; + bidHash: string; + resourceLockInfo: ResourceLockInfo; + resourceLockStatus: string; + createdAt: string; + createdAtEpoch: number; + updatedAt: string; + updatedAtEpoch: number; +} + +export async function getResourceLockInfo(bidHash: string): Promise { + const url = `https://pulse-dss-qa.etherspot.io/pulse/resource-lock-info/${bidHash}`; + const res = await axios.get(url); + return res.data; +} + +// tsx examples/resource-lock/get-resourcelock-info.ts +(async () => { + const info = await getResourceLockInfo('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); + console.log(JSON.stringify(info, null, 2)); +})(); \ No newline at end of file diff --git a/examples/resource-lock/get-session-key-details.ts b/examples/resource-lock/get-session-key-details.ts new file mode 100644 index 0000000..50e3119 --- /dev/null +++ b/examples/resource-lock/get-session-key-details.ts @@ -0,0 +1,54 @@ +import axios from 'axios'; + +export type SessionData = { + sessionKey: string; + validAfter: number; + validUntil: number; + live: boolean; +}; + +export type LockedToken = { + token: string; + locked_amount: string; + claimed_amount: string; +}; + +export type SessionDetails = { + sessionData: SessionData; + lockedTokens: LockedToken[]; +}; + +export async function getAllSessionKeysOfWallet( + chainId: number | string, + walletAddress: string +): Promise { + const url = `https://pulse-dss-qa.etherspot.io/pulse/credible-account/session-details-wallet/chainId/${chainId}/walletAddress/${walletAddress}`; + const res = await axios.get(url); + return res.data; +} + +export async function getSessionDetailsByWalletAddressAndSessionKey( + chainId: number | string, + walletAddress: string, + sessionKey: string +): Promise { + const allSessionKeyDetails = await getAllSessionKeysOfWallet(chainId, walletAddress); + + const sessionDetails = allSessionKeyDetails.find( + (details) => details.sessionData.sessionKey === sessionKey + ); + + return sessionDetails as SessionDetails; +} + +export const bigintReplacer = (key: string, value: any) => { + return typeof value === 'bigint' ? value.toString() : value; +} + +// tsx examples/resource-lock/get-session-key-details.ts +(async () => { + const chainId = 10; + const walletAddress = '0x23F04522a2ec5a8b188C48c18edAE54005b537a3'; + const details = await getAllSessionKeysOfWallet(chainId, walletAddress); + console.log(`details for wallet ${walletAddress} on chain ${chainId} are: ${JSON.stringify(details, bigintReplacer, 2)}`); +})(); \ No newline at end of file diff --git a/examples/resource-lock/get-session-key-pair.ts b/examples/resource-lock/get-session-key-pair.ts index 2601991..f3f2650 100644 --- a/examples/resource-lock/get-session-key-pair.ts +++ b/examples/resource-lock/get-session-key-pair.ts @@ -11,7 +11,7 @@ const client = new SecretsManagerClient({ } }); -async function getSecretFromBidHashAndSessionKey(bidHash: string, sessionKey: string) { +export async function getSecretFromBidHashAndSessionKey(bidHash: string, sessionKey: string) { const secretName = `${sessionKey}-${bidHash}`; console.log(`Fetching secret for: ${secretName}`); if (!secretName) { diff --git a/examples/resource-lock/search-bid.ts b/examples/resource-lock/search-bid.ts new file mode 100644 index 0000000..7dfda5d --- /dev/null +++ b/examples/resource-lock/search-bid.ts @@ -0,0 +1,65 @@ +import axios from 'axios'; +import { bigintReplacer } from './get-session-key-details'; + +// Types for the bid search API response + +export interface BidPath { + tokenConsumed: string; + amountConsumed: string | number; + tokenReceived: string; + amountReceived: string | number; + action: string; +} + +export interface BidSolution { + to: string; + callData: string; + value: string | number; + path: BidPath; +} + +export interface BidStep { + sequenceNumber: number; + chainId: number; + validUntil: number; + solution: BidSolution; +} + +export interface BidDetails { + bidHash: string; + solverAddress: string; + intentHash: string; + steps: BidStep[]; +} + +export interface ExecutedTransaction { + chainId: number; + transactionHash: string; +} + +export interface BidSearchResult { + bidHash: string; + solverAddress: string; + intentHash: string; + bid: BidDetails; + bidStatus: string; + createdAt: string; + createdAtEpoch: number; + updatedAt: string; + updatedAtEpoch: number; + executedAtEpoch: number; + message: string; + executedTransactions: ExecutedTransaction[]; +} + +export async function searchBid(bidHash: string): Promise { + const url = `https://pulse-dss-qa.etherspot.io/pulse/bids/search?bidHash=${bidHash}`; + const res = await axios.get(url); + return res.data; +} + +// tsx examples/resource-lock/search-bid.ts +(async () => { + const results = await searchBid('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); + console.log(JSON.stringify(results, bigintReplacer, 2)); +})(); \ No newline at end of file diff --git a/package.json b/package.json index 9192967..e58a2ab 100644 --- a/package.json +++ b/package.json @@ -63,9 +63,10 @@ "url": "https://github.com/etherspot/etherspot-modular-sdk/issues" }, "dependencies": { - "@lifi/sdk": "2.5.0", + "@aws-sdk/client-secrets-manager": "^3.835.0", "@thehubbleproject/bls": "0.5.1", "@walletconnect/universal-provider": "2.10.0", + "axios": "^1.10.0", "biome": "0.3.3", "class-transformer": "0.5.1", "class-validator": "0.14.1", @@ -90,7 +91,7 @@ "async-mutex": "0.5.0", "buffer": "6.0.3", "bun-types": "1.0.7", - "dotenv": "16.0.3", + "dotenv": "^16.0.3", "eslint": "8.28.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.2.1", From c75f28f1e1cd6f81668949b468d29b756817fb58 Mon Sep 17 00:00:00 2001 From: kanth Date: Fri, 27 Jun 2025 22:24:43 +0530 Subject: [PATCH 20/22] feat: helper functions to query intent and bid data via API calls to DSS-API --- .../claim-resourcelock-session-key.ts | 89 +++++++++++++++++-- examples/resource-lock/search-bid.ts | 75 ++++++++-------- examples/resource-lock/search-intent.ts | 62 +++++++++++++ 3 files changed, 181 insertions(+), 45 deletions(-) create mode 100644 examples/resource-lock/search-intent.ts diff --git a/examples/resource-lock/claim-resourcelock-session-key.ts b/examples/resource-lock/claim-resourcelock-session-key.ts index de565a9..1d15860 100644 --- a/examples/resource-lock/claim-resourcelock-session-key.ts +++ b/examples/resource-lock/claim-resourcelock-session-key.ts @@ -10,42 +10,113 @@ import { getSecretFromBidHashAndSessionKey } from './get-session-key-pair'; import { getSessionDetailsByWalletAddressAndSessionKey, SessionDetails } from './get-session-key-details'; import { BidSearchResult, searchBid } from './search-bid'; import { getResourceLockInfo, ResourceLockInfoResponse } from './get-resourcelock-info'; +import { IntentSearchResult, searchIntent } from './search-intent'; dotenv.config(); -const chainId = 10; const walletPrivateKey = process.env.WALLET_PRIVATE_KEY as string; -const bundlerApiKey = 'etherspot_public_key'; -const user_modular_wallet_address = ''; - -const bidHash = ''; +const bundlerApiKey = process.env.BUNDLER_API_KEY as string; +const bidHash = '0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'; // tsx examples/resource-lock/claim-resourcelock-session-key.ts async function main() { + if (!walletPrivateKey || !bundlerApiKey || !bidHash) { + console.error('Please set the user_modular_wallet_address, walletPrivateKey, bundlerApiKey, and bidHash environment variables.'); + return; + } + // search bid and get solver address const bidSearchResult: BidSearchResult[] = await searchBid(bidHash); + if (!bidSearchResult || bidSearchResult.length === 0) { + console.error(`No bid found for hash: ${bidHash}`); + return; + } + const bidDetails = bidSearchResult[0]; + if (!bidDetails) { + console.error(`No bid found for hash: ${bidHash}`); + return; + } + const solverAddress = bidDetails.solverAddress; + if (!solverAddress) { + console.error(`No solver address found for bid hash: ${bidHash}`); + return; + } + + const intentSearchResultResponse : IntentSearchResult[] = await searchIntent(bidDetails.intentHash); + + if (!intentSearchResultResponse || intentSearchResultResponse.length === 0) { + console.error(`No intent found for hash: ${bidDetails.intentHash}`); + return; + } + + const intentSearchResult: IntentSearchResult = intentSearchResultResponse[0]; + + if (!intentSearchResult || !intentSearchResult.userIntent) { + console.error(`No intent found for hash: ${bidDetails.intentHash}`); + return; + } + + const modularWalletAddress = intentSearchResult.userIntent.core.permittedAccounts[0].account; + const chainId = intentSearchResult.userIntent.core.permittedAccounts[0].chainId; + + if (!modularWalletAddress) { + console.error(`No modular wallet address found for intent hash: ${bidDetails.intentHash}`); + return; + } + const resourceLockInfoResponse: ResourceLockInfoResponse = await getResourceLockInfo(bidHash); + if (!resourceLockInfoResponse || !resourceLockInfoResponse.resourceLockInfo) { + console.error(`No resource lock info found for bid hash: ${bidHash}`); + return; + } + const sessionKeyAddress = resourceLockInfoResponse.resourceLockInfo.sessionKey; + if (!sessionKeyAddress) { + console.error(`No session key address found for bid hash: ${bidHash}`); + return; + } + // get session key private key from AWS Secrets Manager const sessionPrivateKey = await getSecretFromBidHashAndSessionKey(solverAddress, sessionKeyAddress); + if (!sessionPrivateKey) { + console.error(`No session private key found for session key address: ${sessionKeyAddress}`); + return; + } + // get the session-details from api-call const sessionKeyDetails: SessionDetails = await getSessionDetailsByWalletAddressAndSessionKey( chainId, - user_modular_wallet_address, + modularWalletAddress, sessionKeyAddress ); + if (!sessionKeyDetails || !sessionKeyDetails.lockedTokens || sessionKeyDetails.lockedTokens.length === 0) { + console.error(`No locked tokens found for session key address: ${sessionKeyAddress}`); + return; + } + const tokenAddress = sessionKeyDetails.lockedTokens[0].token; - const tokenAmount = sessionKeyDetails.lockedTokens[0].locked_amount; + const lockedAmount = sessionKeyDetails.lockedTokens[0].locked_amount; + const claimedAmount = sessionKeyDetails.lockedTokens[0].claimed_amount; + + if (!tokenAddress || !lockedAmount || !claimedAmount) { + console.error(`Invalid locked token details for session key address: ${sessionKeyAddress}`); + return; + } + + if (claimedAmount == lockedAmount || lockedAmount == '0') { + console.error(`You have already claimed: ${claimedAmount} locked tokens`); + return; + } // prepare UserOp to transfer the locked ERC20 tokens from the user's ModularWallet to the solver address const modularSdk = new ModularSdk( @@ -54,14 +125,14 @@ async function main() { chainId: chainId, bundlerProvider: new EtherspotBundler(chainId, bundlerApiKey), index: 0, - accountAddress: user_modular_wallet_address + accountAddress: modularWalletAddress }) // get transferFrom encoded data const transactionData = encodeFunctionData({ functionName: 'transfer', abi: parseAbi(ERC20_ABI), - args: [solverAddress, tokenAmount] + args: [solverAddress, lockedAmount] }); // clear the transaction batch diff --git a/examples/resource-lock/search-bid.ts b/examples/resource-lock/search-bid.ts index 7dfda5d..e686da7 100644 --- a/examples/resource-lock/search-bid.ts +++ b/examples/resource-lock/search-bid.ts @@ -4,62 +4,65 @@ import { bigintReplacer } from './get-session-key-details'; // Types for the bid search API response export interface BidPath { - tokenConsumed: string; - amountConsumed: string | number; - tokenReceived: string; - amountReceived: string | number; - action: string; + tokenConsumed: string; + amountConsumed: string | number; + tokenReceived: string; + amountReceived: string | number; + action: string; } export interface BidSolution { - to: string; - callData: string; - value: string | number; - path: BidPath; + to: string; + callData: string; + value: string | number; + path: BidPath; } export interface BidStep { - sequenceNumber: number; - chainId: number; - validUntil: number; - solution: BidSolution; + sequenceNumber: number; + chainId: number; + validUntil: number; + solution: BidSolution; } export interface BidDetails { - bidHash: string; - solverAddress: string; - intentHash: string; - steps: BidStep[]; + bidHash: string; + solverAddress: string; + intentHash: string; + steps: BidStep[]; } export interface ExecutedTransaction { - chainId: number; - transactionHash: string; + chainId: number; + transactionHash: string; } export interface BidSearchResult { - bidHash: string; - solverAddress: string; - intentHash: string; - bid: BidDetails; - bidStatus: string; - createdAt: string; - createdAtEpoch: number; - updatedAt: string; - updatedAtEpoch: number; - executedAtEpoch: number; - message: string; - executedTransactions: ExecutedTransaction[]; + bidHash: string; + solverAddress: string; + intentHash: string; + bid: BidDetails; + bidStatus: string; + createdAt: string; + createdAtEpoch: number; + updatedAt: string; + updatedAtEpoch: number; + executedAtEpoch: number; + message: string; + executedTransactions: ExecutedTransaction[]; } export async function searchBid(bidHash: string): Promise { - const url = `https://pulse-dss-qa.etherspot.io/pulse/bids/search?bidHash=${bidHash}`; - const res = await axios.get(url); - return res.data; + const url = `https://pulse-dss-qa.etherspot.io/pulse/bids/search?bidHash=${bidHash}`; + const res = await axios.get(url); + if (res.status !== 200) { + throw new Error(`Failed to fetch bid details for hash: ${bidHash}`); + } + return res.data; } // tsx examples/resource-lock/search-bid.ts (async () => { - const results = await searchBid('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); - console.log(JSON.stringify(results, bigintReplacer, 2)); + const results = await searchBid('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); + console.log(JSON.stringify(results, bigintReplacer, 2)); })(); \ No newline at end of file diff --git a/examples/resource-lock/search-intent.ts b/examples/resource-lock/search-intent.ts new file mode 100644 index 0000000..e75c1f2 --- /dev/null +++ b/examples/resource-lock/search-intent.ts @@ -0,0 +1,62 @@ +import axios from 'axios'; + +// Types for the intent search API response + +export interface PermittedAccount { + account: string; + chainId: number; +} + +export interface DesiredAsset { + asset: string; + value: number | string; + chainId: number; +} + +export interface DispensableAsset { + asset: string; + maxValue: number | string; + chainId: number; +} + +export interface IntentCore { + permittedAccounts: PermittedAccount[]; +} + +export interface IntentConstraints { + permittedChains: number[]; + deadline: number; + maxGas: number; + slippagePercentage: number; + desiredAssets: DesiredAsset[]; + dispensableAssets: DispensableAsset[]; +} + +export interface UserIntent { + intentHash: string; + core: IntentCore; + constraints: IntentConstraints; +} + +export interface IntentSearchResult { + intentHash: string; + intentStatus: string; + userIntent: UserIntent; + account: string; + createdAt: string; + createdAtEpoch: number; + updatedAt: string; + updatedAtEpoch: number; +} + +export async function searchIntent(intentHash: string): Promise { + const url = `https://pulse-dss-qa.etherspot.io/pulse/intents/search?intent_hash=${intentHash}`; + const res = await axios.get(url); + return res.data; +} + +// Example usage: +// (async () => { +// const results = await searchIntent('0xddaea938a9293e91b2556ac656cf30b5cb5cf980748d783db24bf019a1ab4668'); +// console.log(JSON.stringify(results, null, 2)); +// })(); \ No newline at end of file From 896c6bc1da63a1561baf56122495bde1dc4c5ccd Mon Sep 17 00:00:00 2001 From: kanth Date: Sat, 28 Jun 2025 02:02:24 +0530 Subject: [PATCH 21/22] feat: validations on resource-lock release --- .../claim-resourcelock-session-key.ts | 12 +++++++++--- examples/resource-lock/get-resourcelock-info.ts | 8 ++++---- .../resource-lock/get-session-key-details.ts | 17 +++++++++++------ examples/resource-lock/get-session-key-pair.ts | 14 +++++++------- examples/resource-lock/search-bid.ts | 8 ++++---- examples/resource-lock/search-intent.ts | 2 +- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/examples/resource-lock/claim-resourcelock-session-key.ts b/examples/resource-lock/claim-resourcelock-session-key.ts index 1d15860..a23bbe0 100644 --- a/examples/resource-lock/claim-resourcelock-session-key.ts +++ b/examples/resource-lock/claim-resourcelock-session-key.ts @@ -7,7 +7,7 @@ import { ERC20_ABI } from '../../src/sdk/helpers/abi/ERC20_ABI'; import { encodeFunctionData, Hex, parseAbi, parseUnits } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { getSecretFromBidHashAndSessionKey } from './get-session-key-pair'; -import { getSessionDetailsByWalletAddressAndSessionKey, SessionDetails } from './get-session-key-details'; +import { bigintReplacer, getSessionDetailsByWalletAddressAndSessionKey, SessionDetails } from './get-session-key-details'; import { BidSearchResult, searchBid } from './search-bid'; import { getResourceLockInfo, ResourceLockInfoResponse } from './get-resourcelock-info'; import { IntentSearchResult, searchIntent } from './search-intent'; @@ -76,8 +76,14 @@ async function main() { console.error(`No resource lock info found for bid hash: ${bidHash}`); return; } + console.log(`Resource Lock Info: ${JSON.stringify(resourceLockInfoResponse, bigintReplacer, 2)}`); - const sessionKeyAddress = resourceLockInfoResponse.resourceLockInfo.sessionKey; + const sessionKeyAddress = resourceLockInfoResponse.resourceLockInfo.sessionKey; + + if(resourceLockInfoResponse.resourceLockInfo.validUntil < Date.now() / 1000) { + console.error(`SessionKey: ${sessionKeyAddress} expired in Resource lock info for bid hash: ${bidHash}`); + return; + } if (!sessionKeyAddress) { console.error(`No session key address found for bid hash: ${bidHash}`); @@ -85,7 +91,7 @@ async function main() { } // get session key private key from AWS Secrets Manager - const sessionPrivateKey = await getSecretFromBidHashAndSessionKey(solverAddress, sessionKeyAddress); + const sessionPrivateKey = await getSecretFromBidHashAndSessionKey(bidHash, sessionKeyAddress); if (!sessionPrivateKey) { console.error(`No session private key found for session key address: ${sessionKeyAddress}`); diff --git a/examples/resource-lock/get-resourcelock-info.ts b/examples/resource-lock/get-resourcelock-info.ts index 7553f6d..2b6eff4 100644 --- a/examples/resource-lock/get-resourcelock-info.ts +++ b/examples/resource-lock/get-resourcelock-info.ts @@ -44,7 +44,7 @@ export async function getResourceLockInfo(bidHash: string): Promise { - const info = await getResourceLockInfo('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); - console.log(JSON.stringify(info, null, 2)); -})(); \ No newline at end of file +// (async () => { +// const info = await getResourceLockInfo('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); +// console.log(JSON.stringify(info, null, 2)); +// })(); \ No newline at end of file diff --git a/examples/resource-lock/get-session-key-details.ts b/examples/resource-lock/get-session-key-details.ts index 50e3119..bd94ac8 100644 --- a/examples/resource-lock/get-session-key-details.ts +++ b/examples/resource-lock/get-session-key-details.ts @@ -32,8 +32,13 @@ export async function getSessionDetailsByWalletAddressAndSessionKey( walletAddress: string, sessionKey: string ): Promise { + console.log(`Fetching session details for wallet: ${walletAddress}, chainId: ${chainId}, sessionKey: ${sessionKey}`); const allSessionKeyDetails = await getAllSessionKeysOfWallet(chainId, walletAddress); + if (!allSessionKeyDetails || allSessionKeyDetails.length === 0) { + console.error(`No session keys found for wallet: ${walletAddress} on chain: ${chainId}`); + } + const sessionDetails = allSessionKeyDetails.find( (details) => details.sessionData.sessionKey === sessionKey ); @@ -46,9 +51,9 @@ export const bigintReplacer = (key: string, value: any) => { } // tsx examples/resource-lock/get-session-key-details.ts -(async () => { - const chainId = 10; - const walletAddress = '0x23F04522a2ec5a8b188C48c18edAE54005b537a3'; - const details = await getAllSessionKeysOfWallet(chainId, walletAddress); - console.log(`details for wallet ${walletAddress} on chain ${chainId} are: ${JSON.stringify(details, bigintReplacer, 2)}`); -})(); \ No newline at end of file +// (async () => { +// const chainId = 10; +// const walletAddress = '0x23F04522a2ec5a8b188C48c18edAE54005b537a3'; +// const details = await getAllSessionKeysOfWallet(chainId, walletAddress); +// console.log(`details for wallet ${walletAddress} on chain ${chainId} are: ${JSON.stringify(details, bigintReplacer, 2)}`); +// })(); \ No newline at end of file diff --git a/examples/resource-lock/get-session-key-pair.ts b/examples/resource-lock/get-session-key-pair.ts index f3f2650..5d1597a 100644 --- a/examples/resource-lock/get-session-key-pair.ts +++ b/examples/resource-lock/get-session-key-pair.ts @@ -26,10 +26,10 @@ export async function getSecretFromBidHashAndSessionKey(bidHash: string, session throw new Error("Secret not found"); } -// tsx examples/secrets-manager/get-session-key-pair.ts -(async () => { - const bidHash = '0x7931e1aca917a4673d583cdc599bcfe6ff19496922aa75a11499e726884b9aec'; - const sessionKey = '0xd0Df09FD15E6a4b2940A22a684EEC2F377E36a8C'; - const secret = await getSecretFromBidHashAndSessionKey(bidHash, sessionKey); - console.log(secret); -})(); \ No newline at end of file +// tsx examples/resource-lock/get-session-key-pair.ts +// (async () => { +// const bidHash = '0x7931e1aca917a4673d583cdc599bcfe6ff19496922aa75a11499e726884b9aec'; +// const sessionKey = '0xd0Df09FD15E6a4b2940A22a684EEC2F377E36a8C'; +// const secret = await getSecretFromBidHashAndSessionKey(bidHash, sessionKey); +// console.log(secret); +// })(); \ No newline at end of file diff --git a/examples/resource-lock/search-bid.ts b/examples/resource-lock/search-bid.ts index e686da7..8efdea2 100644 --- a/examples/resource-lock/search-bid.ts +++ b/examples/resource-lock/search-bid.ts @@ -62,7 +62,7 @@ export async function searchBid(bidHash: string): Promise { } // tsx examples/resource-lock/search-bid.ts -(async () => { - const results = await searchBid('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); - console.log(JSON.stringify(results, bigintReplacer, 2)); -})(); \ No newline at end of file +// (async () => { +// const results = await searchBid('0xf9385007459e20a6f37805309a73a1eaae824e06ec136ae3b95452229a1ce27f'); +// console.log(JSON.stringify(results, bigintReplacer, 2)); +// })(); \ No newline at end of file diff --git a/examples/resource-lock/search-intent.ts b/examples/resource-lock/search-intent.ts index e75c1f2..386fa7a 100644 --- a/examples/resource-lock/search-intent.ts +++ b/examples/resource-lock/search-intent.ts @@ -55,7 +55,7 @@ export async function searchIntent(intentHash: string): Promise { // const results = await searchIntent('0xddaea938a9293e91b2556ac656cf30b5cb5cf980748d783db24bf019a1ab4668'); // console.log(JSON.stringify(results, null, 2)); From bd367e14dd891c6b41eef271ae90a4afdd6f6c6b Mon Sep 17 00:00:00 2001 From: kanthgithub Date: Tue, 5 Aug 2025 12:48:12 +0530 Subject: [PATCH 22/22] feat: sepolia contract addresses updated --- src/sdk/network/constants.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sdk/network/constants.ts b/src/sdk/network/constants.ts index 31f70ab..fb20d5b 100644 --- a/src/sdk/network/constants.ts +++ b/src/sdk/network/constants.ts @@ -116,9 +116,9 @@ export const Networks: { bootstrap: '0xFD109F06162B76d6A7752B853F4e825Df2cC9cBA', multipleOwnerECDSAValidator: '0x0eA25BF9F313344d422B513e1af679484338518E', erc20SessionKeyValidator: '0x22A55192a663591586241D42E603221eac49ed09', - hookMultiPlexer: '0xDcA918dd23456d321282DF9507F6C09A50522136', - credibleAccountModule: '0xfd090eAFdb3dccE1FA9517ce52BaeBAd1d8cE939', - resourceLockValidator: '0xa3789284adB928258DA2cC674090AC5c69D22183' + hookMultiPlexer: '0xe629A99Fe2fAD23B1dF6Aa680BA6995cfDA885a3', + credibleAccountModule: '0xc34D2E2D9Fa0aDbCd801F13563A1423858751A12', + resourceLockValidator: '0x08B42e03c1beC06caa3811F503EBF2D58CaccE94' }, }, [10]: {