Smart ContractsOther AccountsModular Account V1Multisig

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): AlchemyTransport

Creates 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: Chain
sepolia
} 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 | undefined

The 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 | undefined

The 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 | undefined

The account index to use in the path ("m/44'/60'/$accountIndex'/0/0").

accountIndex
: 2 },
), ]; export const
const threshold: 3n
threshold
= 3n;
export const
const owners: `0x${string}`[]
owners
= await
var Promise: PromiseConstructor

Represents 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: Chain
sepolia
,
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}`[] | undefined
owners
,
threshold: bigint
threshold
,
transport: AlchemyTransportBase & { updateHeaders(newHeaders: HeadersInit): void; config: AlchemyTransportConfig; dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"]; }

The RPC transport

transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "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 multisigAccountClient
multisigAccountClient
} 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: any
request
,
const aggregatedSignature: any
aggregatedSignature
,
any
signatureObj
:
const firstSig: any
firstSig
,
} = await
import multisigAccountClient
multisigAccountClient
.
any
proposeUserOperation
({
uo: { target: any; data: string; }
uo
: {
target: any
target
:
any
targetAddress
,
data: string
data
: "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): AlchemyTransport

Creates 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: Chain
sepolia
} 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 | undefined

The 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 | undefined

The 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 | undefined

The account index to use in the path ("m/44'/60'/$accountIndex'/0/0").

accountIndex
: 2 },
), ]; export const
const threshold: 3n
threshold
= 3n;
export const
const owners: `0x${string}`[]
owners
= await
var Promise: PromiseConstructor

Represents 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: Chain
sepolia
,
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}`[] | undefined
owners
,
threshold: bigint
threshold
,
transport: AlchemyTransportBase & { updateHeaders(newHeaders: HeadersInit): void; config: AlchemyTransportConfig; dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"]; }

The RPC transport

transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "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 signers
signers
,
import owners
owners
,
import threshold
threshold
} 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: any
signer
:
import signers
signers
[1], // using the second signer
owners?: `0x${string}`[] | undefined
owners
,
threshold: bigint
threshold
,
apiKey: string
apiKey
: "YOUR_API_KEY",
}); const {
const aggregatedSignature: `0x${string}`
aggregatedSignature
,
signatureObj: Signature
signatureObj
:
const secondSig: Signature
secondSig
} =
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>> | undefined
account
:
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
: [
any
previousAggregatedSignature
],
userOperationRequest: UserOperationRequest<keyof EntryPointRegistryBase<unknown>>
userOperationRequest
:
any
request
,
});
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): AlchemyTransport

Creates 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: Chain
sepolia
} 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 | undefined

The 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 | undefined

The 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 | undefined

The account index to use in the path ("m/44'/60'/$accountIndex'/0/0").

accountIndex
: 2 },
), ]; export const
const threshold: 3n
threshold
= 3n;
export const
const owners: `0x${string}`[]
owners
= await
var Promise: PromiseConstructor

Represents 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: Chain
sepolia
,
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}`[] | undefined
owners
,
threshold: bigint
threshold
,
transport: AlchemyTransportBase & { updateHeaders(newHeaders: HeadersInit): void; config: AlchemyTransportConfig; dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"]; }

The RPC transport

transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "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 signers
signers
,
import owners
owners
,
import threshold
threshold
} 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: any
signer
:
import signers
signers
[2],
owners?: `0x${string}`[] | undefined
owners
,
threshold: bigint
threshold
,
apiKey: string
apiKey
: "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 | BatchUserOperationCallData
uo
:
any
request
.
any
callData
,
context: MultisigUserOperationContext
context
: {
aggregatedSignature: `0x${string}`
aggregatedSignature
,
signatures: Signature[]
signatures
: [
any
firstSig
,
any
secondSig
],
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): AlchemyTransport

Creates 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: Chain
sepolia
} 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 | undefined

The 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 | undefined

The 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 | undefined

The account index to use in the path ("m/44'/60'/$accountIndex'/0/0").

accountIndex
: 2 },
), ]; export const
const threshold: 3n
threshold
= 3n;
export const
const owners: `0x${string}`[]
owners
= await
var Promise: PromiseConstructor

Represents 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: Chain
sepolia
,
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}`[] | undefined
owners
,
threshold: bigint
threshold
,
transport: AlchemyTransportBase & { updateHeaders(newHeaders: HeadersInit): void; config: AlchemyTransportConfig; dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"]; }

The RPC transport

transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "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 multisigAccountClient
multisigAccountClient
} from "./client";
const
const result: any
result
= await
import multisigAccountClient
multisigAccountClient
.
any
sendUserOperation
({
uo: any
uo
:
any
request
.
any
callData
,
overrides: { callGasLimit: any; verificationGasLimit: any; preVerificationGas: any; maxFeePerGas: any; maxPriorityFeePerGas: any; }
overrides
: {
callGasLimit: any
callGasLimit
:
any
request
.
any
callGasLimit
,
verificationGasLimit: any
verificationGasLimit
:
any
request
.
any
verificationGasLimit
,
preVerificationGas: any
preVerificationGas
:
any
request
.
any
preVerificationGas
,
maxFeePerGas: any
maxFeePerGas
:
any
request
.
any
maxFeePerGas
,
maxPriorityFeePerGas: any
maxPriorityFeePerGas
:
any
request
.
any
maxPriorityFeePerGas
,
},
context: { aggregatedSignature: any; signatures: any[]; userOpSignatureType: string; }
context
: {
aggregatedSignature: any
aggregatedSignature
,
signatures: any[]
signatures
: [
any
firstSig
,
any
secondSig
],
userOpSignatureType: string
userOpSignatureType
: "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): AlchemyTransport

Creates 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: Chain
sepolia
} 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 | undefined

The 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 | undefined

The 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 | undefined

The account index to use in the path ("m/44'/60'/$accountIndex'/0/0").

accountIndex
: 2 },
), ]; export const
const threshold: 3n
threshold
= 3n;
export const
const owners: `0x${string}`[]
owners
= await
var Promise: PromiseConstructor

Represents 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: Chain
sepolia
,
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}`[] | undefined
owners
,
threshold: bigint
threshold
,
transport: AlchemyTransportBase & { updateHeaders(newHeaders: HeadersInit): void; config: AlchemyTransportConfig; dynamicFetchOptions: AlchemyTransportConfig["fetchOptions"]; }

The RPC transport

transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates 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: string
apiKey
: "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.