Smart ContractsOther AccountsModular Account V1Session keys

Getting started with Session Keys

@account-kit/smart-contracts exports all of the definitions you need to use session keys with a Modular Account. We provide a simple SessionKeySigner class that generates session keys on the client and can be used as the signer for the Multi Owner Modular Account. We also export the necessary decorators which can be used to extend your modularAccountClient to make interacting with session keys easy.

Usage

Let’s take a look at a full example that demonstrates how to use session keys with a Modular Account.

/* eslint-disable @typescript-eslint/no-unused-vars */
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 {
enum SessionKeyAccessListType
SessionKeyAccessListType
,
class SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
,
const SessionKeyPlugin: Plugin<readonly [{ readonly type: "function"; readonly name: "addSessionKey"; readonly inputs: readonly [{ readonly name: "sessionKey"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "tag"; readonly type: "bytes32"; readonly internalType: "bytes32"; }, { readonly name: "permissionUpdates"; readonly type: "bytes[]"; readonly internalType: "bytes[]"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, ... 43 more ..., { ...; }]>
SessionKeyPlugin
,
class SessionKeySigner

A simple session key signer that uses localStorage or sessionStorage to store a private key. If the key is not found, it will generate a new one and store it in the storage.

SessionKeySigner
,
function createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
,
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
,
} from "@account-kit/smart-contracts"; import {
const zeroHash: "0x0000000000000000000000000000000000000000000000000000000000000000"
zeroHash
} from "viem";
const
const chain: Chain
chain
=
const sepolia: Chain
sepolia
;
const
const transport: AlchemyTransport
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" });
// this is the signer to connect with the account, later we will create a new client using a session key signe const
const signer: LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>
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>.mnemonicToAccountSigner(key: string, opts?: HDOptions): LocalAccountSigner<HDAccount>

Creates a LocalAccountSigner using the provided mnemonic key and optional HD options.

mnemonicToAccountSigner
("MNEMONIC");
const
const sessionKeySigner: SessionKeySigner
sessionKeySigner
= new
new SessionKeySigner(config_?: SessionKeySignerConfig): SessionKeySigner

Initializes a new instance of a session key signer with the provided configuration. This will set the signerType, storageKey, and storageType. It will also manage the session key, either fetching it from storage or generating a new one if it doesn't exist.

SessionKeySigner
();
const
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
= (
await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
transport: AlchemyTransport

The RPC transport

transport
,
signer: LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>
signer
,
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, keyof EntryPointRegistryBase<...>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);
// 1. check if the plugin is installed const
const isPluginInstalled: boolean
isPluginInstalled
= await
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
.
function getInstalledPlugins(args: { account?: SmartContractAccount<string, keyof EntryPointRegistryBase<unknown>> | undefined; }): Promise<ReadonlyArray<Address>>
getInstalledPlugins
({})
// This checks using the default address for the chain, but you can always pass in your own plugin address here as an override .
Promise<readonly `0x${string}`[]>.then<boolean, never>(onfulfilled?: ((value: readonly `0x${string}`[]) => boolean | PromiseLike<boolean>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>

Attaches callbacks for the resolution and/or rejection of the Promise.

then
((
x: readonly `0x${string}`[]
x
) =>
x: readonly `0x${string}`[]
x
.
ReadonlyArray<`0x${string}`>.includes(searchElement: `0x${string}`, fromIndex?: number): boolean

Determines whether an array includes a certain element, returning true or false as appropriate.

includes
(
const SessionKeyPlugin: Plugin<readonly [{ readonly type: "function"; readonly name: "addSessionKey"; readonly inputs: readonly [{ readonly name: "sessionKey"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "tag"; readonly type: "bytes32"; readonly internalType: "bytes32"; }, { readonly name: "permissionUpdates"; readonly type: "bytes[]"; readonly internalType: "bytes[]"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, ... 43 more ..., { ...; }]>
SessionKeyPlugin
.
meta: { name: string; version: string; addresses: Record<number, Address>; }
meta
.
addresses: Record<number, `0x${string}`>
addresses
[
const chain: Chain
chain
.
id: number

ID in number form

id
]));
// 2. if the plugin is not installed, then install it and set up the session key if (!
const isPluginInstalled: boolean
isPluginInstalled
) {
// lets create an initial permission set for the session key giving it an eth spend limit const
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
= new
new SessionKeyPermissionsBuilder(): SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
()
.
SessionKeyPermissionsBuilder.setNativeTokenSpendLimit(limit: NativeTokenLimit): SessionKeyPermissionsBuilder

Sets the native token spend limit and returns the instance for chaining.

setNativeTokenSpendLimit
({
spendLimit: bigint
spendLimit
: 1000000n,
}) // this will allow the session key plugin to interact with all addresses .
SessionKeyPermissionsBuilder.setContractAccessControlType(aclType: SessionKeyAccessListType): SessionKeyPermissionsBuilder

Sets the access control type for the contract and returns the current instance for method chaining.

setContractAccessControlType
(
enum SessionKeyAccessListType
SessionKeyAccessListType
.
function (enum member) SessionKeyAccessListType.ALLOW_ALL_ACCESS = 2
ALLOW_ALL_ACCESS
)
.
SessionKeyPermissionsBuilder.setTimeRange(timeRange: TimeRange): SessionKeyPermissionsBuilder

Sets the time range for an object and returns the object itself for chaining.

setTimeRange
({
validFrom: number
validFrom
:
var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

Math
.
Math.round(x: number): number

Returns a supplied numeric expression rounded to the nearest integer.

round
(
var Date: DateConstructor

Enables basic storage and retrieval of dates and times.

Date
.
DateConstructor.now(): number

Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).

now
() / 1000),
// valid for 1 hour
validUntil: number
validUntil
:
var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

Math
.
Math.round(x: number): number

Returns a supplied numeric expression rounded to the nearest integer.

round
(
var Date: DateConstructor

Enables basic storage and retrieval of dates and times.

Date
.
DateConstructor.now(): number

Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).

now
() / 1000 + 60 * 60),
}); const {
const hash: `0x${string}`
hash
} = await
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
.
installSessionKeyPlugin: (args: { overrides?: UserOperationOverrides<keyof EntryPointRegistryBase<unknown>> | undefined; } & InstallSessionKeyPluginParams & { ...; } & { ...; }) => Promise<...>
installSessionKeyPlugin
({
// 1st arg is the initial set of session keys // 2nd arg is the tags for the session keys // 3rd arg is the initial set of permissions
args: [readonly `0x${string}`[], readonly `0x${string}`[], readonly (readonly `0x${string}`[])[]]
args
: [
[await
const sessionKeySigner: SessionKeySigner
sessionKeySigner
.
SessionKeySigner.getAddress: () => Promise<`0x${string}`>

An async function that retrieves the address using the inner object's getAddress method.

getAddress
()],
[
const zeroHash: "0x0000000000000000000000000000000000000000000000000000000000000000"
zeroHash
],
[
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
.
SessionKeyPermissionsBuilder.encode(): Hex[]

Encodes various function calls into an array of hexadecimal strings based on the provided permissions and limits.

encode
()],
], }); await
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
.
waitForUserOperationTransaction: (args: WaitForUserOperationTxParameters) => Promise<Hex>
waitForUserOperationTransaction
({
hash: `0x${string}`
hash
});
} // 3. set up a client that's using our session key const
const sessionKeyClient: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<SessionKeySigner>, [{ Method: "eth_sendUserOperation"; Parameters: [UserOperationRequest, Address]; ReturnType: Hash; }, ... 50 more ..., { ...; }], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
sessionKeyClient
= (
await
createModularAccountAlchemyClient<SessionKeySigner>(params: AlchemyModularAccountClientConfig<SessionKeySigner>): Promise<{ account: MultiOwnerModularAccount<SessionKeySigner>; ... 100 more ...; extend: <client>(fn: (client: Client<...>) => client) => Client<...>; }>
createModularAccountAlchemyClient
({
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
signer: SessionKeySigner
signer
:
const sessionKeySigner: SessionKeySigner
sessionKeySigner
,
transport: AlchemyTransport

The RPC transport

transport
,
// this is important because it tells the client to use our previously deployed account
accountAddress?: `0x${string}` | undefined
accountAddress
:
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
.
getAddress: () => Address
getAddress
({
account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>
account
:
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
.
account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>

The Account of the Client.

account
}),
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<SessionKeySigner>, keyof EntryPointRegistryBase<unknown>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);
// 4. send a user operation using the session key const
const result: SendUserOperationResult<keyof EntryPointRegistryBase<unknown>>
result
= await
const sessionKeyClient: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<SessionKeySigner>, [{ Method: "eth_sendUserOperation"; Parameters: [UserOperationRequest, Address]; ReturnType: Hash; }, ... 50 more ..., { ...; }], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
sessionKeyClient
.
executeWithSessionKey: (args: Pick<EncodeFunctionDataParameters<readonly [{ readonly type: "function"; readonly name: "executeWithSessionKey"; readonly inputs: readonly [{ readonly name: "calls"; readonly type: "tuple[]"; readonly internalType: "struct Call[]"; readonly components: readonly [{ readonly name: "target"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "value"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "data"; readonly type: "bytes"; readonly internalType: "bytes"; }]; }, { readonly name: "sessionKey"; readonly type: "address"; readonly internalType: "address"; }]; readonly outputs: readonly [{ readonly name: ""; readonly type: "bytes[]"; readonly internalType: "bytes[]"; }]; readonly stateMutability: "nonpayable"; }, { ...; }, { ...; }, { ...; }, { ...; }], "executeWithSessionKey">, "args"> & { ...; } & { ...; } & { ...; }) => Promise<...>
executeWithSessionKey
({
args: readonly [readonly { target: `0x${string}`; value: bigint; data: `0x${string}`; }[], `0x${string}`]
args
: [
[ {
target: `0x${string}`
target
: "0x1234123412341234123412341234123412341234",
value: bigint
value
: 1n,
data: `0x${string}`
data
: "0x",
}, ], await
const sessionKeySigner: SessionKeySigner
sessionKeySigner
.
SessionKeySigner.getAddress: () => Promise<`0x${string}`>

An async function that retrieves the address using the inner object's getAddress method.

getAddress
(),
], });

Breaking it down

Determine where the session key is stored

Session keys can be held on the client side or on a backend agent. Client side session keys are useful for skipping confirmations, and agent side keys are useful for automations.

In the above example, we use a client-side key using the SessionKeySigner exported from @account-kit/smart-contracts.

import { 
class SessionKeySigner

A simple session key signer that uses localStorage or sessionStorage to store a private key. If the key is not found, it will generate a new one and store it in the storage.

SessionKeySigner
} from "@account-kit/smart-contracts";
const
const sessionKeySigner: SessionKeySigner
sessionKeySigner
= new
new SessionKeySigner(config_?: SessionKeySignerConfig): SessionKeySigner

Initializes a new instance of a session key signer with the provided configuration. This will set the signerType, storageKey, and storageType. It will also manage the session key, either fetching it from storage or generating a new one if it doesn't exist.

SessionKeySigner
();

If you are using backend agent controlled session keys, then the agent should generate the private key and send only the address to the client. This protects the private key by not exposing it to the user.

Extend your client with Modular Account Decorators

The base modularAccountClient and AlchemymodularAccountClient, only include base functionality for sending user operations. If you are using a ModularAccount, then you will want to extend your client with the various decorators exported by @account-kit/smart-contracts.

import { 
import modularAccountClient
modularAccountClient
} from "./client";
import {
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
} from "@account-kit/smart-contracts";
const
const extendedClient: any
extendedClient
=
import modularAccountClient
modularAccountClient
.
any
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
} from "@account-kit/smart-contracts";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
export const
const chain: Chain
chain
=
const sepolia: Chain
sepolia
;
export const
const modularAccountClient: { account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 100 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
modularAccountClient
= await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
()),
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
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" }),
});

Check if the Session Key Plugin is installed

Before you can start using session keys, you need to check whether the user’s account has the session key plugin installed. You can perform this check using the account loupe decorator, which lets you inspect the state of installed plugins on a Modular Account.


import { 
const SessionKeyPlugin: Plugin<readonly [{ readonly type: "function"; readonly name: "addSessionKey"; readonly inputs: readonly [{ readonly name: "sessionKey"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "tag"; readonly type: "bytes32"; readonly internalType: "bytes32"; }, { readonly name: "permissionUpdates"; readonly type: "bytes[]"; readonly internalType: "bytes[]"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, ... 43 more ..., { ...; }]>
SessionKeyPlugin
} from "@account-kit/smart-contracts";
// 1. check if the plugin is installed const
const isPluginInstalled: any
isPluginInstalled
= await
import modularAccountClient
modularAccountClient
.
any
getInstalledPlugins
({})
// This checks using the default address for the chain, but you can always pass in your own plugin address here as an override .
any
then
((
x: any
x
) =>
x: any
x
.
any
includes
(
const SessionKeyPlugin: Plugin<readonly [{ readonly type: "function"; readonly name: "addSessionKey"; readonly inputs: readonly [{ readonly name: "sessionKey"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "tag"; readonly type: "bytes32"; readonly internalType: "bytes32"; }, { readonly name: "permissionUpdates"; readonly type: "bytes[]"; readonly internalType: "bytes[]"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, ... 43 more ..., { ...; }]>
SessionKeyPlugin
.
meta: { name: string; version: string; addresses: Record<number, Address>; }
meta
.
addresses: Record<number, `0x${string}`>
addresses
[
any
chain
.
any
id
]));
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
} from "@account-kit/smart-contracts";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
export const
const chain: Chain
chain
=
const sepolia: Chain
sepolia
;
export const
const modularAccountClient: { account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 100 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
modularAccountClient
= await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
()),
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
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" }),
});

Install the Session Key Plugin

If the Session Key Plugin is not yet installed, you need to install it before it can be used. To simplify the workflow, it is also possible to batch the plugin installation along with creating session keys and performing other actions, which combines all of these steps into one user operation.

import { 
class SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
} from "@account-kit/smart-contracts";
// 2. if the plugin is not installed, then install it and set up the session key if (!
const isPluginInstalled: any
isPluginInstalled
) {
// lets create an initial permission set for the session key giving it an eth spend limit // if we don't set anything here, then the key will have 0 permissions const
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
=
new
new SessionKeyPermissionsBuilder(): SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
().
SessionKeyPermissionsBuilder.setNativeTokenSpendLimit(limit: NativeTokenLimit): SessionKeyPermissionsBuilder

Sets the native token spend limit and returns the instance for chaining.

setNativeTokenSpendLimit
({
spendLimit: bigint
spendLimit
: 1000000n,
}); const {
const hash: any
hash
} = await
const extendedClient: any
extendedClient
.
any
installSessionKeyPlugin
({
// 1st arg is the initial set of session keys // 2nd arg is the tags for the session keys // 3rd arg is the initial set of permissions
args: any[][]
args
: [
[await
any
sessionKeySigner
.
any
getAddress
()],
[
any
zeroHash
],
[
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
.
SessionKeyPermissionsBuilder.encode(): Hex[]

Encodes various function calls into an array of hexadecimal strings based on the provided permissions and limits.

encode
()],
], }); await
const extendedClient: any
extendedClient
.
any
waitForUserOperationTransaction
({
hash: any
hash
});
}
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
} from "@account-kit/smart-contracts";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
export const
const chain: Chain
chain
=
const sepolia: Chain
sepolia
;
export const
const modularAccountClient: { account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 100 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
modularAccountClient
= await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
()),
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
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" }),
});

Construct the initial set of permissions

Session keys are powerful because of permissions that limit what actions they can take. When you add a session key, you should also specify the initial permissions that apply over the key.

See the Supported Permissions page for more information on how to used the permissions builder.

Let’s use the permission builder to build a set of permissions that sets a spend limit:

import { 
class SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
} from "@account-kit/smart-contracts";
const
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
=
new
new SessionKeyPermissionsBuilder(): SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
().
SessionKeyPermissionsBuilder.setNativeTokenSpendLimit(limit: NativeTokenLimit): SessionKeyPermissionsBuilder

Sets the native token spend limit and returns the instance for chaining.

setNativeTokenSpendLimit
({
spendLimit: bigint
spendLimit
: 1000000n,
}); const
const result: any
result
= await
const extendedClient: any
extendedClient
.
any
updateKeyPermissions
({
args: any[]
args
: [
any
sessionKeyAddress
,
const initialPermissions: SessionKeyPermissionsBuilder
initialPermissions
.
SessionKeyPermissionsBuilder.encode(): Hex[]

Encodes various function calls into an array of hexadecimal strings based on the provided permissions and limits.

encode
()],
});
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
} from "@account-kit/smart-contracts";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
export const
const chain: Chain
chain
=
const sepolia: Chain
sepolia
;
export const
const modularAccountClient: { account: MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>; ... 100 more ...; extend: <const client extends { ...; } & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>; }
modularAccountClient
= await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
()),
chain: { blockExplorers?: { [key: string]: ChainBlockExplorer; default: ChainBlockExplorer; } | undefined; ... 7 more ...; testnet?: boolean | undefined; } & ChainConfig<...>

Chain for the client.

chain
,
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" }),
});

Managing Session Keys

The Session Key Plugin allows you to:

  • Add session keys, and set the key’s initial permissions.
  • Remove session keys.
  • Update key permissions.
  • Rotate session keys. This action replaces the previous session key with a new session key, while keeping the existing permissions.

Add a Session Key

Session keys can be added either during installation, or using the addSessionKey function.

import { 
class SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
} from "@account-kit/smart-contracts";
import {
function keccak256<to extends To = "hex">(value: Hex | ByteArray, to_?: to | undefined): Keccak256Hash<to>
keccak256
} from "viem";
import {
import client
client
} from "./base-client";
const
const result: any
result
= await
import client
client
.
any
addSessionKey
({
key: string
key
: "0xSessionKeyAddress",
// tag is an identifier for the emitted SessionKeyAdded event
tag: `0x${string}`
tag
:
keccak256<"hex">(value: Hex | ByteArray, to_?: "hex" | undefined): `0x${string}`
keccak256
(new
var TextEncoder: new () => TextEncoder

TextEncoder class is a global reference for import TextEncoder from 'node:util' https://nodejs.org/api/globals.html#textencoder

TextEncoder
().
TextEncoder.encode(input?: string): Uint8Array

UTF-8 encodes the input string and returns a Uint8Array containing the encoded bytes.

encode
("session-key-tag")),
permissions: `0x${string}`[]
permissions
: new
new SessionKeyPermissionsBuilder(): SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
().
SessionKeyPermissionsBuilder.encode(): Hex[]

Encodes various function calls into an array of hexadecimal strings based on the provided permissions and limits.

encode
(),
});
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
,
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
,
} from "@account-kit/smart-contracts"; export const
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
= (
await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
:
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
("MNEMONIC"),
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
: "ALCHEMY_API_KEY" }),
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, keyof EntryPointRegistryBase<...>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);

Remove a Session Key

Session keys can be removed using the removeSessionKey function.

import { 
import client
client
} from "./base-client";
const
const result: any
result
= await
import client
client
.
any
removeSessionKey
({
key: string
key
: "0xSessionKeyAddress",
});
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
,
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
,
} from "@account-kit/smart-contracts"; export const
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
= (
await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
:
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
("MNEMONIC"),
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
: "ALCHEMY_API_KEY" }),
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, keyof EntryPointRegistryBase<...>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);

Update a Key’s permissions

Session key permissions can be edited after creation using the updateKeyPermissions function. Note that you should configure initial permissions when the key is added, and not rely on a second user operation to set the permissions.

import { 
class SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
} from "@account-kit/smart-contracts";
import {
import client
client
} from "./base-client";
const
const result: any
result
= await
import client
client
.
any
updateSessionKeyPermissions
({
key: string
key
: "0xSessionKeyAddress",
// add other permissions to the builder
permissions: `0x${string}`[]
permissions
: new
new SessionKeyPermissionsBuilder(): SessionKeyPermissionsBuilder

A builder for creating the hex-encoded data for updating session key permissions.

SessionKeyPermissionsBuilder
()
.
SessionKeyPermissionsBuilder.setTimeRange(timeRange: TimeRange): SessionKeyPermissionsBuilder

Sets the time range for an object and returns the object itself for chaining.

setTimeRange
({
validFrom: number
validFrom
:
var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

Math
.
Math.round(x: number): number

Returns a supplied numeric expression rounded to the nearest integer.

round
(
var Date: DateConstructor

Enables basic storage and retrieval of dates and times.

Date
.
DateConstructor.now(): number

Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).

now
() / 1000),
// valid for 1 hour
validUntil: number
validUntil
:
var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

Math
.
Math.round(x: number): number

Returns a supplied numeric expression rounded to the nearest integer.

round
(
var Date: DateConstructor

Enables basic storage and retrieval of dates and times.

Date
.
DateConstructor.now(): number

Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC).

now
() / 1000 + 60 * 60),
}) .
SessionKeyPermissionsBuilder.encode(): Hex[]

Encodes various function calls into an array of hexadecimal strings based on the provided permissions and limits.

encode
(),
});
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
,
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
,
} from "@account-kit/smart-contracts"; export const
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
= (
await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
:
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
("MNEMONIC"),
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
: "ALCHEMY_API_KEY" }),
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, keyof EntryPointRegistryBase<...>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);

Rotate a Session Key

If the key is no longer available, but there exists a tag identifying a previous session key configured for your application, you may instead choose to rotate the previous key’s permissions. This can be performed using rotateKey .

import { 
import client
client
} from "./base-client.js";
const
const result: any
result
= await
import client
client
.
any
rotateSessionKey
({
oldKey: string
oldKey
: "0xOldKey",
newKey: string
newKey
: "0xNewKey",
});
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 createModularAccountAlchemyClient<TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(params: AlchemyModularAccountClientConfig<TSigner>): Promise<AlchemySmartAccountClient<Chain | undefined, MultiOwnerModularAccount<TSigner>, MultiOwnerPluginActions<MultiOwnerModularAccount<TSigner>> & PluginManagerActions<MultiOwnerModularAccount<TSigner>> & AccountLoupeActions<MultiOwnerModularAccount<TSigner>>>>
createModularAccountAlchemyClient
,
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
,
} from "@account-kit/smart-contracts"; export const
const client: Client<AlchemyTransport, Chain | undefined, MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, [...], { ...; } & ... 11 more ... & AlchemySmartAccountClientActions<...>>
client
= (
await
createModularAccountAlchemyClient<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>(params: AlchemyModularAccountClientConfig<...>): Promise<...>
createModularAccountAlchemyClient
({
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
:
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
("MNEMONIC"),
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
: "ALCHEMY_API_KEY" }),
}) ).
extend: <SessionKeyPluginActions<MultiOwnerModularAccount<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 7 more ...; getHdKey: () => HDKey; }>>, keyof EntryPointRegistryBase<...>>>(fn: (client: Client<...>) => SessionKeyPluginActions<...>) => Client<...>
extend
(
const sessionKeyPluginActions: <TTransport extends Transport = Transport, TChain extends Chain | undefined = Chain | undefined, TAccount extends SmartContractAccount | undefined = SmartContractAccount | undefined>(client: Client<TTransport, TChain, TAccount>) => SessionKeyPluginActions<TAccount>

Creates actions for managing session keys in a smart contract associated with a client, including adding, removing, rotating, and updating session key permissions.

sessionKeyPluginActions
);