Managing ownership

You can add an owner to your account, or transfer ownership of your account with Modular Account V2.

To transfer ownership, we call the updateFallbackSignerData function. Modular Account V2s achieve huge savings on creation because we cache the owner address in immutable bytecode on account creation. When transferring ownership, we set the fallback signer to the new owner address and this will be used during validation. We set the boolean to false for the account to check this value in storage instead of the immutable cached owner address.

Note that updateFallbackSignerData is an ownership transfer operation, and the previous owner would lose access to the account. To add an owner, you should add a session key with root permissions instead.

import { 
function createModularAccountV2Client<TChain extends Chain = Chain, TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(args: CreateModularAccountV2AlchemyClientParams<AlchemyTransport, TChain, TSigner>): Promise<ModularAccountV2Client<TSigner, TChain, AlchemyTransport>> (+1 overload)
createModularAccountV2Client
} from "@account-kit/smart-contracts";
import {
const semiModularAccountBytecodeAbi: readonly [{ readonly type: "constructor"; readonly inputs: readonly [{ readonly name: "entryPoint"; readonly type: "address"; readonly internalType: "contract IEntryPoint"; }, { readonly name: "executionInstallDelegate"; readonly type: "address"; readonly internalType: "contract ExecutionInstallDelegate"; }]; readonly stateMutability: "nonpayable"; }, ... 60 more ..., { ...; }]
semiModularAccountBytecodeAbi
} from "@account-kit/smart-contracts/experimental";
import { type
interface SmartAccountSigner<Inner = any>

A signer that can sign messages and typed data.

SmartAccountSigner
,
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 generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
import {
function encodeFunctionData<const abi extends Abi | readonly unknown[], functionName extends ContractFunctionName<abi> | undefined = undefined>(parameters: EncodeFunctionDataParameters<abi, functionName>): EncodeFunctionDataReturnType
encodeFunctionData
} from "viem";
import {
const sepolia: Chain
sepolia
,
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
} from "@account-kit/infra";
const
const client: { [x: string]: unknown; account: ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 84 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
client
= await
createModularAccountV2Client<Chain, LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>(args: CreateModularAccountV2AlchemyClientParams<...>): Promise<...> (+1 overload)
createModularAccountV2Client
({
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
:
const sepolia: Chain
sepolia
,
transport: AlchemyTransport

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" }),
signer: LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>
signer
:
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>.privateKeyToAccountSigner(key: Hex): LocalAccountSigner<PrivateKeyAccount>

Creates a LocalAccountSigner instance using the provided private key.

privateKeyToAccountSigner
(
function generatePrivateKey(): Hex
generatePrivateKey
()),
}); const
const newOwner: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
newOwner
= "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
// The boolean parameter in updateFallbackSignerData is `isFallbackSignerDisabled`, and false indicates that we are using the value of the fallback signer await
const client: { [x: string]: unknown; account: ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 84 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
client
.
sendUserOperation: (args: SendUserOperationParameters<ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, UserOperationContext | undefined, keyof EntryPointRegistryBase<...>>) => Promise<...>
sendUserOperation
({
uo: UserOperationCallData | BatchUserOperationCallData
uo
: {
target: `0x${string}`
target
:
const client: { [x: string]: unknown; account: ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 84 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
client
.
account: ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>

The Account of the Client.

account
.
address: `0x${string}`
address
,
value?: bigint | undefined
value
: 0n,
data: `0x${string}`
data
:
encodeFunctionData<readonly [{ readonly type: "constructor"; readonly inputs: readonly [{ readonly name: "entryPoint"; readonly type: "address"; readonly internalType: "contract IEntryPoint"; }, { readonly name: "executionInstallDelegate"; readonly type: "address"; readonly internalType: "contract ExecutionInstallDelegate"; }]; readonly stateMutability: "nonpayable"; }, ... 60 more ..., { ...; }], "updateFallbackSignerData">(parameters: EncodeFunctionDataParameters<...>): EncodeFunctionDataReturnType
encodeFunctionData
({
abi: readonly [{ readonly type: "constructor"; readonly inputs: readonly [{ readonly name: "entryPoint"; readonly type: "address"; readonly internalType: "contract IEntryPoint"; }, { readonly name: "executionInstallDelegate"; readonly type: "address"; readonly internalType: "contract ExecutionInstallDelegate"; }]; readonly stateMutability: "nonpayable"; }, ... 60 more ..., { ...; }]
abi
:
const semiModularAccountBytecodeAbi: readonly [{ readonly type: "constructor"; readonly inputs: readonly [{ readonly name: "entryPoint"; readonly type: "address"; readonly internalType: "contract IEntryPoint"; }, { readonly name: "executionInstallDelegate"; readonly type: "address"; readonly internalType: "contract ExecutionInstallDelegate"; }]; readonly stateMutability: "nonpayable"; }, ... 60 more ..., { ...; }]
semiModularAccountBytecodeAbi
,
functionName: `0x${string}` | "entryPoint" | "updateFallbackSignerData" | "accountId" | "execute" | "executeBatch" | "executeUserOp" | "executeWithRuntimeValidation" | "getExecutionData" | ... 14 more ... | "validateUserOp"
functionName
: "updateFallbackSignerData",
args: readonly [`0x${string}`, boolean]
args
: [
const newOwner: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
newOwner
, false],
}), }, });