Removing Session Keys

Session Keys are currently an experimental feature in the SDK. We are actively working on simplifying the usage, please note that there could be breaking changes as we improve this feature.

Removing session keys is done with the uninstallValidation method.

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 installValidationActions: <TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(client: ModularAccountV2Client<TSigner>) => InstallValidationActions<TSigner>

Provides validation installation and uninstallation functionalities for a MA v2 client, ensuring compatibility with SmartAccountClient.

installValidationActions
,
const getDefaultSingleSignerValidationModuleAddress: (chain: Chain) => Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
,
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
,
const modularAccountAbi: 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"; }, ... 54 more ..., { ...; }]
modularAccountAbi
,
} from "@account-kit/smart-contracts/experimental"; 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 {
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";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
const
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
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
()),
}) ).
extend: <InstallValidationActions<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>>(fn: (client: Client<...>) => InstallValidationActions<...>) => Client<...>
extend
(
const installValidationActions: <TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(client: ModularAccountV2Client<TSigner>) => InstallValidationActions<TSigner>

Provides validation installation and uninstallation functionalities for a MA v2 client, ensuring compatibility with SmartAccountClient.

installValidationActions
);
let
let sessionKeyEntityId: number
sessionKeyEntityId
= 1;
// Removing a basic session key await
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
uninstallValidation: (args: UninstallValidationParams<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>) => Promise<SendUserOperationResult>
uninstallValidation
({
moduleAddress: `0x${string}`
moduleAddress
:
function getDefaultSingleSignerValidationModuleAddress(chain: Chain): Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
(
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
chain: Chain

Chain for the client.

chain
),
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
uninstallData: `0x${string}`
uninstallData
:
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
.
encodeOnUninstallData: (args: { entityId: number; }) => Hex
encodeOnUninstallData
({
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
}),
hookUninstallDatas: `0x${string}`[]
hookUninstallDatas
: [],
}); // Removing a session key with hooks await
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
uninstallValidation: (args: UninstallValidationParams<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>) => Promise<SendUserOperationResult>
uninstallValidation
({
moduleAddress: `0x${string}`
moduleAddress
:
function getDefaultSingleSignerValidationModuleAddress(chain: Chain): Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
(
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
chain: Chain

Chain for the client.

chain
),
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
uninstallData: `0x${string}`
uninstallData
:
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
.
encodeOnUninstallData: (args: { entityId: number; }) => Hex
encodeOnUninstallData
({
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
}),
hookUninstallDatas: `0x${string}`[]
hookUninstallDatas
: [],
});

If there are hooks on the validation, you have to provide the hook uninstallation data to uninstall them too. Each module provides an encodeOnUninstallData helper function to generate the uninstallation hook for that module.

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 installValidationActions: <TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(client: ModularAccountV2Client<TSigner>) => InstallValidationActions<TSigner>

Provides validation installation and uninstallation functionalities for a MA v2 client, ensuring compatibility with SmartAccountClient.

installValidationActions
,
const getDefaultSingleSignerValidationModuleAddress: (chain: Chain) => Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
,
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
,
const modularAccountAbi: 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"; }, ... 54 more ..., { ...; }]
modularAccountAbi
,
const AllowlistModule: { abi: readonly [{ readonly type: "function"; readonly name: "addressAllowlist"; readonly inputs: readonly [{ readonly name: "entityId"; readonly type: "uint32"; readonly internalType: "uint32"; }, { readonly name: "target"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "account"; readonly type: "address"; readonly internalType: "address"; }]; readonly outputs: readonly [{ readonly name: "allowed"; readonly type: "bool"; readonly internalType: "bool"; }, { readonly name: "hasSelectorAllowlist"; readonly type: "bool"; readonly internalType: "bool"; }, { readonly name: "hasERC20SpendLimit"; readonly type: "bool"; readonly internalType: "bool"; }]; readonly stateMutability: "view"; }, { readonly type: "function"; readonly name: "checkAllowlistCalldata"; readonly inputs: readonly [{ readonly name: "entityId"; readonly type: "uint32"; readonly internalType: "uint32"; }, { readonly name: "callData"; readonly type: "bytes"; readonly internalType: "bytes"; }]; readonly outputs: readonly []; readonly stateMutability: "view"; }, { readonly type: "function"; readonly name: "deleteAllowlist"; readonly ...
AllowlistModule
,
} from "@account-kit/smart-contracts/experimental"; 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 {
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";
import {
function generatePrivateKey(): Hex
generatePrivateKey
} from "viem/accounts";
const
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
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
()),
}) ).
extend: <InstallValidationActions<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>>(fn: (client: Client<...>) => InstallValidationActions<...>) => Client<...>
extend
(
const installValidationActions: <TSigner extends SmartAccountSigner = SmartAccountSigner<any>>(client: ModularAccountV2Client<TSigner>) => InstallValidationActions<TSigner>

Provides validation installation and uninstallation functionalities for a MA v2 client, ensuring compatibility with SmartAccountClient.

installValidationActions
);
let
let sessionKeyEntityId: number
sessionKeyEntityId
= 1;
// Removing a basic session key await
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
uninstallValidation: (args: UninstallValidationParams<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>) => Promise<SendUserOperationResult>
uninstallValidation
({
moduleAddress: `0x${string}`
moduleAddress
:
function getDefaultSingleSignerValidationModuleAddress(chain: Chain): Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
(
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
chain: Chain

Chain for the client.

chain
),
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
uninstallData: `0x${string}`
uninstallData
:
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
.
encodeOnUninstallData: (args: { entityId: number; }) => Hex
encodeOnUninstallData
({
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
}),
hookUninstallDatas: `0x${string}`[]
hookUninstallDatas
: [],
}); const
const hookEntityId: 1
hookEntityId
= 1;
const
const target: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
target
= "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
// Removing a session key with an allowlist hook await
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
uninstallValidation: (args: UninstallValidationParams<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>) => Promise<SendUserOperationResult>
uninstallValidation
({
moduleAddress: `0x${string}`
moduleAddress
:
function getDefaultSingleSignerValidationModuleAddress(chain: Chain): Address

Maps a given chain to a specific address of the single signer validation module by its chain ID. If no direct mapping exists, it defaults to returning a specific address.

getDefaultSingleSignerValidationModuleAddress
(
const client: Client<AlchemyTransport, Chain, ModularAccountV2<LocalAccountSigner<{ address: Address; nonceManager?: NonceManager | undefined; sign: (parameters: { hash: Hash; }) => Promise<Hex>; ... 6 more ...; type: "local"; }>>, [...], { ...; } & ... 4 more ... & PublicActions>
client
.
chain: Chain

Chain for the client.

chain
),
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
uninstallData: `0x${string}`
uninstallData
:
const SingleSignerValidationModule: { encodeOnInstallData: (args: { entityId: number; signer: Address; }) => Hex; encodeOnUninstallData: (args: { entityId: number; }) => Hex; }
SingleSignerValidationModule
.
encodeOnUninstallData: (args: { entityId: number; }) => Hex
encodeOnUninstallData
({
entityId: number
entityId
:
let sessionKeyEntityId: number
sessionKeyEntityId
,
}),
hookUninstallDatas: `0x${string}`[]
hookUninstallDatas
: [
const AllowlistModule: { abi: readonly [{ readonly type: "function"; readonly name: "addressAllowlist"; readonly inputs: readonly [{ readonly name: "entityId"; readonly type: "uint32"; readonly internalType: "uint32"; }, { readonly name: "target"; readonly type: "address"; readonly internalType: "address"; }, { readonly name: "account"; readonly type: "address"; readonly internalType: "address"; }]; readonly outputs: readonly [{ readonly name: "allowed"; readonly type: "bool"; readonly internalType: "bool"; }, { readonly name: "hasSelectorAllowlist"; readonly type: "bool"; readonly internalType: "bool"; }, { readonly name: "hasERC20SpendLimit"; readonly type: "bool"; readonly internalType: "bool"; }]; readonly stateMutability: "view"; }, { readonly type: "function"; readonly name: "checkAllowlistCalldata"; readonly inputs: readonly [{ readonly name: "entityId"; readonly type: "uint32"; readonly internalType: "uint32"; }, { readonly name: "callData"; readonly type: "bytes"; readonly internalType: "bytes"; }]; readonly outputs: readonly []; readonly stateMutability: "view"; }, { readonly type: "function"; readonly name: "deleteAllowlist"; readonly ...
AllowlistModule
.
encodeOnUninstallData: (args: { entityId: number; inputs: Array<{ target: Address; hasSelectorAllowlist: boolean; hasERC20SpendLimit: boolean; erc20SpendLimit: bigint; selectors: Array<Hex>; }>; }) => Hex
encodeOnUninstallData
({
entityId: number
entityId
:
const hookEntityId: 1
hookEntityId
,
inputs: { target: Address; hasSelectorAllowlist: boolean; hasERC20SpendLimit: boolean; erc20SpendLimit: bigint; selectors: Array<Hex>; }[]
inputs
: [
{
target: `0x${string}`
target
,
hasSelectorAllowlist: boolean
hasSelectorAllowlist
: false,
hasERC20SpendLimit: boolean
hasERC20SpendLimit
: false,
erc20SpendLimit: bigint
erc20SpendLimit
: 0n,
selectors: `0x${string}`[]
selectors
: [],
}, ], }), ], });