diff --git a/aa-sdk/core/src/account/smartContractAccount.ts b/aa-sdk/core/src/account/smartContractAccount.ts index ed2f790d59..5e736e4071 100644 --- a/aa-sdk/core/src/account/smartContractAccount.ts +++ b/aa-sdk/core/src/account/smartContractAccount.ts @@ -151,9 +151,11 @@ export type ToSmartContractAccountParams< getDummySignature: () => Hex | Promise; encodeExecute: (tx: AccountOp) => Promise; encodeBatchExecute?: (txs: AccountOp[]) => Promise; + getNonce?: (nonceKey?: bigint) => Promise; // if not provided, will default to just using signMessage over the Hex signUserOperationHash?: (uoHash: Hex) => Promise; encodeUpgradeToAndCall?: (params: UpgradeToAndCallParams) => Promise; + getImplementationAddress?: () => Promise; } & Omit; // [!endregion ToSmartContractAccountParams] @@ -260,6 +262,7 @@ export async function toSmartContractAccount< source, accountAddress, getAccountInitCode, + getNonce, signMessage, signTypedData, encodeBatchExecute, @@ -339,11 +342,13 @@ export async function toSmartContractAccount( getAccountInitCode, signMessage, signTypedData, - encodeBatchExecute, encodeExecute, + encodeBatchExecute, + getNonce, getDummySignature, signUserOperationHash, encodeUpgradeToAndCall, + getImplementationAddress, } = params; const client = createBundlerClient({ @@ -410,16 +415,18 @@ export async function toSmartContractAccount( return initCode === "0x"; }; - const getNonce = async (nonceKey = 0n): Promise => { - if (!(await isAccountDeployed())) { - return 0n; - } - - return entryPointContract.read.getNonce([ - accountAddress_, - nonceKey, - ]) as Promise; - }; + const getNonce_ = + getNonce ?? + (async (nonceKey = 0n): Promise => { + if (!(await isAccountDeployed())) { + return 0n; + } + + return entryPointContract.read.getNonce([ + accountAddress_, + nonceKey, + ]) as Promise; + }); const account = toAccount({ address: accountAddress_, @@ -468,25 +475,27 @@ export async function toSmartContractAccount( return create6492Signature(isDeployed, signature); }; - const getImplementationAddress = async (): Promise => { - const storage = await client.getStorageAt({ - address: account.address, - // This is the default slot for the implementation address for Proxies - slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + const getImplementationAddress_ = + getImplementationAddress ?? + (async () => { + const storage = await client.getStorageAt({ + address: account.address, + // This is the default slot for the implementation address for Proxies + slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + }); + + if (storage == null) { + throw new FailedToGetStorageSlotError( + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + "Proxy Implementation Address" + ); + } + + // The storage slot contains a full bytes32, but we want only the last 20 bytes. + // So, slice off the leading `0x` and the first 12 bytes (24 characters), leaving the last 20 bytes, then prefix with `0x`. + return `0x${storage.slice(26)}`; }); - if (storage == null) { - throw new FailedToGetStorageSlotError( - "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", - "Proxy Implementation Address" - ); - } - - // The storage slot contains a full bytes32, but we want only the last 20 bytes. - // So, slice off the leading `0x` and the first 12 bytes (24 characters), leaving the last 20 bytes, then prefix with `0x`. - return `0x${storage.slice(26)}`; - }; - if (entryPoint.version !== "0.6.0" && entryPoint.version !== "0.7.0") { throw new InvalidEntryPointError(chain, entryPoint.version); } @@ -510,9 +519,9 @@ export async function toSmartContractAccount( encodeUpgradeToAndCall: encodeUpgradeToAndCall_, getEntryPoint: () => entryPoint, isAccountDeployed, - getAccountNonce: getNonce, + getAccountNonce: getNonce_, signMessageWith6492, signTypedDataWith6492, - getImplementationAddress, + getImplementationAddress: getImplementationAddress_, }; } diff --git a/account-kit/smart-contracts/src/ma-v2/account/common/modularAccountV2Base.ts b/account-kit/smart-contracts/src/ma-v2/account/common/modularAccountV2Base.ts index ef56db5439..c26b6a0c27 100644 --- a/account-kit/smart-contracts/src/ma-v2/account/common/modularAccountV2Base.ts +++ b/account-kit/smart-contracts/src/ma-v2/account/common/modularAccountV2Base.ts @@ -3,8 +3,8 @@ import { getEntryPoint, InvalidEntityIdError, InvalidNonceKeyError, + toSmartContractAccount, type AccountOp, - type EntryPointDef, type SmartAccountSigner, type SmartContractAccountWithSigner, type ToSmartContractAccountParams, @@ -24,6 +24,8 @@ import { } from "viem"; import { modularAccountAbi } from "../../abis/modularAccountAbi.js"; import { serializeModuleEntity } from "../../actions/common/utils.js"; +import { nativeSMASigner } from "../nativeSMASigner.js"; +import { singleSignerMessageSigner } from "../../modules/single-signer-validation/signer.js"; export const executeUserOpSelector: Hex = "0x8DD7712F"; @@ -57,8 +59,9 @@ export type ValidationDataParams = }; export type MAV2Account< - TSigner extends SmartAccountSigner = SmartAccountSigner -> = SmartContractAccountWithSigner<"MAV2Account", TSigner, "0.7.0"> & { + TSigner extends SmartAccountSigner = SmartAccountSigner, + Name extends string = string +> = SmartContractAccountWithSigner & { signerEntity: SignerEntity; getExecutionData: (selector: Hex) => Promise; getValidationData: ( @@ -68,32 +71,47 @@ export type MAV2Account< }; export type CreateMAV2BaseFunctionsParams< - TTransport extends Transport = Transport -> = Pick< - ToSmartContractAccountParams<"MAV2Account", TTransport, Chain, "0.7.0">, - "transport" | "chain" + TTransport extends Transport = Transport, + TSigner extends SmartAccountSigner = SmartAccountSigner, + Name extends string = string +> = Omit< + ToSmartContractAccountParams, + // Implements the following methods required by `toSmartContractAccount`, and passes through any other parameters. + | "encodeExecute" + | "encodeBatchExecute" + | "getNonce" + | "signMessage" + | "signTypedData" + | "getDummySignature" > & { - // salt?: bigint; - // factoryAddress?: Address; - // initCode?: Hex; - // initialOwner?: Address; - entryPoint?: EntryPointDef<"0.7.0", Chain>; + signer: TSigner; signerEntity?: SignerEntity; accountAddress: Address; }; -export async function createMAv2BaseFunctions( +export type CreateMAV2BaseReturnType< + TSigner extends SmartAccountSigner = SmartAccountSigner, + Name extends string = string +> = Promise>; + +export async function createMAv2Base( config: CreateMAV2BaseFunctionsParams -) { +): CreateMAV2BaseReturnType { const { transport, chain, + signer, entryPoint = getEntryPoint(chain, { version: "0.7.0" }), + signerEntity = { + isGlobalValidation: true, + entityId: DEFAULT_OWNER_ENTITY_ID, + }, signerEntity: { isGlobalValidation = true, entityId = DEFAULT_OWNER_ENTITY_ID, } = {}, accountAddress, + ...remainingToSmartContractAccountParams } = config; if (entityId > Number(maxUint32)) { @@ -136,7 +154,7 @@ export async function createMAv2BaseFunctions( const isAccountDeployed: () => Promise = async () => !!(await client.getCode({ address: accountAddress })); // TODO: add deferred action flag - const getAccountNonce = async (nonceKey: bigint = 0n): Promise => { + const getNonce = async (nonceKey: bigint = 0n): Promise => { if (nonceKey > maxUint152) { throw new InvalidNonceKeyError(nonceKey); } @@ -206,12 +224,26 @@ export async function createMAv2BaseFunctions( : callData; }; + const baseAccount = await toSmartContractAccount({ + ...remainingToSmartContractAccountParams, + transport, + chain, + entryPoint, + accountAddress, + encodeExecute, + encodeBatchExecute, + getNonce, + ...(entityId === DEFAULT_OWNER_ENTITY_ID + ? nativeSMASigner(signer, chain, accountAddress) + : singleSignerMessageSigner(signer, chain, accountAddress, entityId)), + }); + return { + ...baseAccount, + getSigner: () => signer, + signerEntity, getExecutionData, getValidationData, encodeCallData, - getAccountNonce, - encodeExecute, - encodeBatchExecute, }; } diff --git a/account-kit/smart-contracts/src/ma-v2/account/semiModularAccount7702.ts b/account-kit/smart-contracts/src/ma-v2/account/semiModularAccount7702.ts index 383776d916..80c08e4227 100644 --- a/account-kit/smart-contracts/src/ma-v2/account/semiModularAccount7702.ts +++ b/account-kit/smart-contracts/src/ma-v2/account/semiModularAccount7702.ts @@ -3,19 +3,13 @@ import type { SmartAccountSigner, ToSmartContractAccountParams, } from "@aa-sdk/core"; -import { - getEntryPoint, - toSmartContractAccount, - EntityIdOverrideError, -} from "@aa-sdk/core"; +import { getEntryPoint, EntityIdOverrideError } from "@aa-sdk/core"; import { type Chain, type Hex, type Transport, type Address } from "viem"; import { DEFAULT_OWNER_ENTITY_ID } from "../utils.js"; -import { singleSignerMessageSigner } from "../modules/single-signer-validation/signer.js"; -import { nativeSMASigner } from "./nativeSMASigner.js"; import { type SignerEntity, type MAV2Account, - createMAv2BaseFunctions, + createMAv2Base, } from "./common/modularAccountV2Base.js"; export type CreateSMA7702AccountParams< @@ -76,38 +70,19 @@ export async function createSMA7702Account( throw new EntityIdOverrideError(); } - const { encodeExecute, encodeBatchExecute, ...baseFunctions } = - await createMAv2BaseFunctions({ - transport, - chain, - entryPoint, - signerEntity, - accountAddress: _accountAddress, - }); + const implementation: Address = "0x69007702764179f14F51cdce752f4f775d74E139"; + + const getImplementationAddress = async () => implementation; - const baseAccount = await toSmartContractAccount({ + return createMAv2Base({ + source: "SMA7702Account", transport, chain, + signer, entryPoint, + signerEntity, accountAddress: _accountAddress, - source: `MAV2Account`, - encodeExecute, - encodeBatchExecute, getAccountInitCode, - ...(entityId === DEFAULT_OWNER_ENTITY_ID - ? nativeSMASigner(signer, chain, _accountAddress) - : singleSignerMessageSigner(signer, chain, _accountAddress, entityId)), - }); - - const implementation: Address = "0x69007702764179f14F51cdce752f4f775d74E139"; - - const getImplementationAddress = async () => implementation; - - return { - ...baseAccount, - ...baseFunctions, - getSigner: () => signer, - signerEntity, getImplementationAddress, - }; + }); } diff --git a/account-kit/smart-contracts/src/ma-v2/account/semiModularAccountV2.ts b/account-kit/smart-contracts/src/ma-v2/account/semiModularAccountV2.ts index c0f6d44b32..970724ffdc 100644 --- a/account-kit/smart-contracts/src/ma-v2/account/semiModularAccountV2.ts +++ b/account-kit/smart-contracts/src/ma-v2/account/semiModularAccountV2.ts @@ -6,7 +6,6 @@ import type { import { createBundlerClient, getEntryPoint, - toSmartContractAccount, getAccountAddress, } from "@aa-sdk/core"; import { @@ -18,16 +17,11 @@ import { type Transport, } from "viem"; import { accountFactoryAbi } from "../abis/accountFactoryAbi.js"; -import { - getDefaultMAV2FactoryAddress, - DEFAULT_OWNER_ENTITY_ID, -} from "../utils.js"; -import { singleSignerMessageSigner } from "../modules/single-signer-validation/signer.js"; -import { nativeSMASigner } from "./nativeSMASigner.js"; +import { getDefaultMAV2FactoryAddress } from "../utils.js"; import { type SignerEntity, type MAV2Account, - createMAv2BaseFunctions, + createMAv2Base, } from "./common/modularAccountV2Base.js"; export type CreateSMAV2AccountParams< @@ -73,11 +67,7 @@ export async function createSMAV2Account( initialOwner, accountAddress, entryPoint = getEntryPoint(chain, { version: "0.7.0" }), - signerEntity = { - isGlobalValidation: true, - entityId: DEFAULT_OWNER_ENTITY_ID, - }, - signerEntity: { entityId = DEFAULT_OWNER_ENTITY_ID } = {}, + signerEntity, } = config; const client = createBundlerClient({ @@ -110,33 +100,14 @@ export async function createSMAV2Account( getAccountInitCode, }); - const { encodeExecute, encodeBatchExecute, ...baseFunctions } = - await createMAv2BaseFunctions({ - transport, - chain, - entryPoint, - signerEntity, - accountAddress: _accountAddress, - }); - - const baseAccount = await toSmartContractAccount({ + return createMAv2Base({ + source: `SMAV2Account`, transport, chain, + signer, entryPoint, accountAddress: _accountAddress, - source: `MAV2Account`, - encodeExecute, - encodeBatchExecute, getAccountInitCode, - ...(entityId === DEFAULT_OWNER_ENTITY_ID - ? nativeSMASigner(signer, chain, _accountAddress) - : singleSignerMessageSigner(signer, chain, _accountAddress, entityId)), - }); - - return { - ...baseAccount, - ...baseFunctions, - getSigner: () => signer, signerEntity, - }; + }); } diff --git a/site/pages/reference/account-kit/infra/functions/alchemyGasManagerMiddleware.mdx b/site/pages/reference/account-kit/infra/functions/alchemyGasManagerMiddleware.mdx index 7fbd8327b1..6d484a1301 100644 --- a/site/pages/reference/account-kit/infra/functions/alchemyGasManagerMiddleware.mdx +++ b/site/pages/reference/account-kit/infra/functions/alchemyGasManagerMiddleware.mdx @@ -18,13 +18,13 @@ import { alchemyGasManagerMiddleware } from "@account-kit/infra"; ## Usage ```ts -import { sepolia, alchemyErc7677Middleware } from "@account-kit/infra"; +import { sepolia, alchemyGasManagerMiddleware } from "@account-kit/infra"; import { http } from "viem"; const client = createSmartAccountClient({ transport: http("rpc-url"), chain: sepolia, - ...alchemyErc7677Middleware("policyId"), + ...alchemyGasManagerMiddleware("policyId"), }); ```