Modular Account with Multisig Plugin • Getting started
1. Create a Multisig Account Client
Initialize a Multisig Modular Account client and set the n
accounts as signers.
It is recommended to use the createMultisigAccountAlchemyClient
directly to create new accounts with multi-sig ownership, rather than extending the Modular Account client.
If you have an existing Modular Account (which has multi-owner plugin by default), please see details here for installing the plugin before proceeding.
import { class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner } from "@aa-sdk/core";
import { function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy, const sepolia: Chainsepolia } from "@account-kit/infra";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC = "YOUR MNEMONIC";
// Creating a 3/3 multisig account
export const const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers = [
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 0 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 1 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 2 },
),
];
export const const threshold: 3nthreshold = 3n;
export const const owners: `0x${string}`[]owners = await var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.all<Promise<`0x${string}`>[]>(values: Promise<`0x${string}`>[]): Promise<`0x${string}`[]> (+1 overload)Creates a Promise that is resolved with an array of results when all of the provided Promises resolve, or rejected when any Promise is rejected.
all(const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers.Array<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>.map<Promise<`0x${string}`>>(callbackfn: (value: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>, index: number, array: LocalAccountSigner<...>[]) => Promise<...>, thisArg?: any): Promise<...>[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s) => s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s.LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>.getAddress: () => Promise<`0x${string}`>Returns the address of the inner object in a specific hexadecimal format.
getAddress()));
export const const multisigAccountClient: {
account: MultisigModularAccount<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>;
... 103 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>(params: AlchemyMultisigAccountClientConfig<...>): Promise<...>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain: const sepolia: Chainsepolia,
signer: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>signer: const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers[0],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
transport: AlchemyTransportBase & {
updateHeaders(newHeaders: HeadersInit): void;
config: AlchemyTransportConfig;
dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"];
}The RPC transport
transport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({
apiKey: stringapiKey: "YOUR_API_KEY",
}),
});
3. Propose a User Operation
To propose a new user operation for review by the multisig signers, you will use the proposeUserOperation
method. This estimates gas, constructs the user operation struct, and if gasManagerConfig
is used then it attempts to use a paymaster. Lastly, a signature is generated with the pre-provided signer.
import { import multisigAccountClientmultisigAccountClient } from "./client";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const {
const request: anyrequest,
const aggregatedSignature: anyaggregatedSignature,
anysignatureObj: const firstSig: anyfirstSig,
} = await import multisigAccountClientmultisigAccountClient.anyproposeUserOperation({
uo: {
target: any;
data: string;
}uo: {
target: anytarget: anytargetAddress,
data: stringdata: "0x",
},
});
import { class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner } from "@aa-sdk/core";
import { function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy, const sepolia: Chainsepolia } from "@account-kit/infra";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC = "YOUR MNEMONIC";
// Creating a 3/3 multisig account
export const const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers = [
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 0 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 1 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 2 },
),
];
export const const threshold: 3nthreshold = 3n;
export const const owners: `0x${string}`[]owners = await var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.all<Promise<`0x${string}`>[]>(values: Promise<`0x${string}`>[]): Promise<`0x${string}`[]> (+1 overload)Creates a Promise that is resolved with an array of results when all of the provided Promises resolve, or rejected when any Promise is rejected.
all(const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers.Array<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>.map<Promise<`0x${string}`>>(callbackfn: (value: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>, index: number, array: LocalAccountSigner<...>[]) => Promise<...>, thisArg?: any): Promise<...>[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s) => s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s.LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>.getAddress: () => Promise<`0x${string}`>Returns the address of the inner object in a specific hexadecimal format.
getAddress()));
export const const multisigAccountClient: {
account: MultisigModularAccount<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>;
... 103 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>(params: AlchemyMultisigAccountClientConfig<...>): Promise<...>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain: const sepolia: Chainsepolia,
signer: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>signer: const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers[0],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
transport: AlchemyTransportBase & {
updateHeaders(newHeaders: HeadersInit): void;
config: AlchemyTransportConfig;
dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"];
}The RPC transport
transport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({
apiKey: stringapiKey: "YOUR_API_KEY",
}),
});
4. Get the threshold signatures
Next, you have to collect the next k-2 signatures, excluding the first signature which you already provided and the last signature which we’ll deal with in step 5 when we send the user operation. Each member of the multisig can sign with the signMultisigUserOperation
method.
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
import { import signerssigners, import ownersowners, import thresholdthreshold } from "./client";
const const multisigAccountClient: {
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<any>(params: AlchemyMultisigAccountClientConfig<any>): Promise<{
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <client>(fn: (client: Client<...>) => client) => Client<...>;
}>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain,
signer: anysigner: import signerssigners[1], // using the second signer
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
apiKey: stringapiKey: "YOUR_API_KEY",
});
const { const aggregatedSignature: `0x${string}`aggregatedSignature, signatureObj: SignaturesignatureObj: const secondSig: SignaturesecondSig } =
await const multisigAccountClient: {
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient.signMultisigUserOperation: (params: SignMultisigUserOperationParams<MultisigModularAccount<any>>) => Promise<SignMultisigUserOperationResult>signMultisigUserOperation({
account?: SmartContractAccount<string, keyof EntryPointRegistryBase<unknown>> | undefinedaccount: const multisigAccountClient: {
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient.account: MultisigModularAccount<any>The Account of the Client.
account,
// output from step 1, and from this step if k-2 > 1
signatures: Signature[]signatures: [anypreviousAggregatedSignature],
userOperationRequest: UserOperationRequest<keyof EntryPointRegistryBase<unknown>>userOperationRequest: anyrequest,
});
import { class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner } from "@aa-sdk/core";
import { function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy, const sepolia: Chainsepolia } from "@account-kit/infra";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC = "YOUR MNEMONIC";
// Creating a 3/3 multisig account
export const const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers = [
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 0 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 1 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 2 },
),
];
export const const threshold: 3nthreshold = 3n;
export const const owners: `0x${string}`[]owners = await var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.all<Promise<`0x${string}`>[]>(values: Promise<`0x${string}`>[]): Promise<`0x${string}`[]> (+1 overload)Creates a Promise that is resolved with an array of results when all of the provided Promises resolve, or rejected when any Promise is rejected.
all(const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers.Array<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>.map<Promise<`0x${string}`>>(callbackfn: (value: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>, index: number, array: LocalAccountSigner<...>[]) => Promise<...>, thisArg?: any): Promise<...>[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s) => s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s.LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>.getAddress: () => Promise<`0x${string}`>Returns the address of the inner object in a specific hexadecimal format.
getAddress()));
export const const multisigAccountClient: {
account: MultisigModularAccount<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>;
... 103 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>(params: AlchemyMultisigAccountClientConfig<...>): Promise<...>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain: const sepolia: Chainsepolia,
signer: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>signer: const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers[0],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
transport: AlchemyTransportBase & {
updateHeaders(newHeaders: HeadersInit): void;
config: AlchemyTransportConfig;
dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"];
}The RPC transport
transport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({
apiKey: stringapiKey: "YOUR_API_KEY",
}),
});
5. Send the User Operation
After collecting k-1 signatures, you’re ready to collect the last signature and send the user operation. This is done with the sendUserOperation
method. sendUserOperation
also formats this aggregated signature, sorting its parts in ascending order by owner address as expected by the Multisig Plugin smart contract.
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
import { import signerssigners, import ownersowners, import thresholdthreshold } from "./client";
const const multisigAccountClient: {
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<any>(params: AlchemyMultisigAccountClientConfig<any>): Promise<{
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <client>(fn: (client: Client<...>) => client) => Client<...>;
}>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain,
// using the last signer
signer: anysigner: import signerssigners[2],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
apiKey: stringapiKey: "YOUR_API_KEY",
});
const const result: SendUserOperationResult<keyof EntryPointRegistryBase<unknown>>result = await const multisigAccountClient: {
account: MultisigModularAccount<any>;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
... 102 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient.sendUserOperation: (args: SendUserOperationParameters<MultisigModularAccount<any>, MultisigUserOperationContext, keyof EntryPointRegistryBase<unknown>>) => Promise<...>sendUserOperation({
uo: UserOperationCallData | BatchUserOperationCallDatauo: anyrequest.anycallData,
context: MultisigUserOperationContextcontext: {
aggregatedSignature: `0x${string}`aggregatedSignature,
signatures: Signature[]signatures: [anyfirstSig, anysecondSig],
userOpSignatureType: "ACTUAL"userOpSignatureType: "ACTUAL",
},
});
import { class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner } from "@aa-sdk/core";
import { function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy, const sepolia: Chainsepolia } from "@account-kit/infra";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC = "YOUR MNEMONIC";
// Creating a 3/3 multisig account
export const const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers = [
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 0 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 1 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 2 },
),
];
export const const threshold: 3nthreshold = 3n;
export const const owners: `0x${string}`[]owners = await var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.all<Promise<`0x${string}`>[]>(values: Promise<`0x${string}`>[]): Promise<`0x${string}`[]> (+1 overload)Creates a Promise that is resolved with an array of results when all of the provided Promises resolve, or rejected when any Promise is rejected.
all(const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers.Array<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>.map<Promise<`0x${string}`>>(callbackfn: (value: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>, index: number, array: LocalAccountSigner<...>[]) => Promise<...>, thisArg?: any): Promise<...>[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s) => s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s.LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>.getAddress: () => Promise<`0x${string}`>Returns the address of the inner object in a specific hexadecimal format.
getAddress()));
export const const multisigAccountClient: {
account: MultisigModularAccount<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>;
... 103 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>(params: AlchemyMultisigAccountClientConfig<...>): Promise<...>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain: const sepolia: Chainsepolia,
signer: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>signer: const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers[0],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
transport: AlchemyTransportBase & {
updateHeaders(newHeaders: HeadersInit): void;
config: AlchemyTransportConfig;
dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"];
}The RPC transport
transport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({
apiKey: stringapiKey: "YOUR_API_KEY",
}),
});
By default, we use the variable gas feature in the Multisig Plugin smart contract. For this, we need userOpSignatureType
to be set to “ACTUAL”. If you do not wish to use this feature, gas overrides should be passed in sendUserOperation
, and userOpSignatureType
should be set to “UPPERLIMIT”.
import { import multisigAccountClientmultisigAccountClient } from "./client";
const const result: anyresult = await import multisigAccountClientmultisigAccountClient.anysendUserOperation({
uo: anyuo: anyrequest.anycallData,
overrides: {
callGasLimit: any;
verificationGasLimit: any;
preVerificationGas: any;
maxFeePerGas: any;
maxPriorityFeePerGas: any;
}overrides: {
callGasLimit: anycallGasLimit: anyrequest.anycallGasLimit,
verificationGasLimit: anyverificationGasLimit: anyrequest.anyverificationGasLimit,
preVerificationGas: anypreVerificationGas: anyrequest.anypreVerificationGas,
maxFeePerGas: anymaxFeePerGas: anyrequest.anymaxFeePerGas,
maxPriorityFeePerGas: anymaxPriorityFeePerGas: anyrequest.anymaxPriorityFeePerGas,
},
context: {
aggregatedSignature: any;
signatures: any[];
userOpSignatureType: string;
}context: {
aggregatedSignature: anyaggregatedSignature,
signatures: any[]signatures: [anyfirstSig, anysecondSig],
userOpSignatureType: stringuserOpSignatureType: "UPPERLIMIT",
},
});
import { class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner } from "@aa-sdk/core";
import { function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy, const sepolia: Chainsepolia } from "@account-kit/infra";
import { function createMultisigAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyMultisigAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultisigModularAccount<TSigner>, MultisigPluginActions<MultisigModularAccount<TSigner>> & PluginManagerActions<MultisigModularAccount<TSigner>> & AccountLoupeActions<MultisigModularAccount<TSigner>>, MultisigUserOperationContext>>createMultisigAccountAlchemyClient } from "@account-kit/smart-contracts";
const const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC = "YOUR MNEMONIC";
// Creating a 3/3 multisig account
export const const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers = [
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 0 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 1 },
),
class LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>Represents a local account signer and provides methods to sign messages and transactions, as well as static methods to create the signer from mnemonic or private key.
LocalAccountSigner.LocalAccountSigner<T extends HDAccount | PrivateKeyAccount | LocalAccount>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.
mnemonicToAccountSigner(
const MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC: "YOUR MNEMONIC"MODULAR_MULTISIG_ACCOUNT_OWNER_MNEMONIC,
{ accountIndex?: number | undefinedThe account index to use in the path ("m/44'/60'/$accountIndex'/0/0"
).
accountIndex: 2 },
),
];
export const const threshold: 3nthreshold = 3n;
export const const owners: `0x${string}`[]owners = await var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.all<Promise<`0x${string}`>[]>(values: Promise<`0x${string}`>[]): Promise<`0x${string}`[]> (+1 overload)Creates a Promise that is resolved with an array of results when all of the provided Promises resolve, or rejected when any Promise is rejected.
all(const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers.Array<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>.map<Promise<`0x${string}`>>(callbackfn: (value: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>, index: number, array: LocalAccountSigner<...>[]) => Promise<...>, thisArg?: any): Promise<...>[]Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s) => s: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>s.LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>.getAddress: () => Promise<`0x${string}`>Returns the address of the inner object in a specific hexadecimal format.
getAddress()));
export const const multisigAccountClient: {
account: MultisigModularAccount<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>;
... 103 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}multisigAccountClient = await createMultisigAccountAlchemyClient<LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>>(params: AlchemyMultisigAccountClientConfig<...>): Promise<...>createMultisigAccountAlchemyClient({
chain: {
blockExplorers?: {
[key: string]: ChainBlockExplorer;
default: ChainBlockExplorer;
} | undefined;
... 7 more ...;
testnet?: boolean | undefined;
} & ChainConfig<...>Chain for the client.
chain: const sepolia: Chainsepolia,
signer: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>signer: const signers: LocalAccountSigner<{
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
... 7 more ...;
getHdKey: () => HDKey;
}>[]signers[0],
owners?: `0x${string}`[] | undefinedowners,
threshold: bigintthreshold,
transport: AlchemyTransportBase & {
updateHeaders(newHeaders: HeadersInit): void;
config: AlchemyTransportConfig;
dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"];
}The RPC transport
transport: function alchemy(config: AlchemyTransportConfig): AlchemyTransportCreates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.
alchemy({
apiKey: stringapiKey: "YOUR_API_KEY",
}),
});
Conclusion
That’s it! You’ve initialized a modular account with three multisig members, proposed a user operation, collected the necessary signatures, and sent the user operation to the bundler.
For more info, check out the technical details of the multisig plugin.