SVG Definitions

ECDSA Session Key

Create a Multichain ECDSA session key with policy-based permissions

Session keys are delegated keys that can sign UserOps on behalf of a smart account, but only within a set of explicit policies. You keep your primary signer offline and issue a scoped session key for a dapp, bot, or background agent. The policies act as guardrails: they define what the session key can call, how much gas it can spend, and when it can be used.

With the Multi-Chain ECDSA validator, a single approval can authorize the same session key across multiple chains. Under the hood, the per-chain permission accounts are hashed into a Merkle tree of UserOp hashes, and the owner signs the root once. Each chain verifies the session key with a Merkle proof instead of a fresh signature, which reduces prompts and keeps permissions consistent across networks.


Import

import { createAccountClient } from "@namera-ai/sdk/account";
import { createSessionKey, createSessionKeyClient } from "@namera-ai/sdk/session-key";

Usage

To create a multichain ECDSA session key, you:

  1. Create your primary smart account client.
  2. Create a session key with policies.
  3. Build a session key client from the serialized account.
index.ts
import { createAccountClient } from "@namera-ai/sdk/account";
import { createSessionKey, createSessionKeyClient } from "@namera-ai/sdk/session-key";
import { http } from "viem";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
import { publicClient } from "./clients";

const signer = privateKeyToAccount(generatePrivateKey());

const accountClient = await createAccountClient({
  type: "ecdsa",
  signer,
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  chain: mainnet,
  client: publicClient,
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
});

const sessionPrivateKey = generatePrivateKey();
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);

const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [
    // Policies for this session key
  ],
  sessionPrivateKey,
  signer,
});

const serializedAccount = sessionKey.serializedAccounts[0]
  ?.serializedAccount as string;

const sessionKeyClient = await createSessionKeyClient({
  type: "ecdsa",
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  chain: mainnet,
  client: publicClient,
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount,
  sessionKeySigner,
});

// Use sessionKeyClient to send UserOps with the session key.

Examples

Create a multichain ECDSA session key with a paymaster, then build a session key client.

index.ts
import { createAccountClient } from "@namera-ai/sdk/account";
import {
  createSessionKey,
  createSessionKeyClient,
} from "@namera-ai/sdk/session-key";
import { createPublicClient, http } from "viem";
import { createPaymasterClient } from "viem/account-abstraction";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";

export const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(),
});

const paymaster = createPaymasterClient({
  transport: http("ZERO_DEV_PAYMASTER_URL"),
});

const signer = privateKeyToAccount(generatePrivateKey());

const client = await createAccountClient({
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  chain: mainnet,
  client: publicClient,
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  paymaster,
  signer,
  type: "ecdsa",
});

const sessionPrivateKey = generatePrivateKey();
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);

const sessionKey = await createSessionKey({
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [
    // Policies for this session key
  ],
  sessionPrivateKey,
  signer,
  type: "ecdsa",
});

const serializedAccount = sessionKey.serializedAccounts[0]
  ?.serializedAccount as string;

const sessionKeyClient = await createSessionKeyClient({
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  chain: mainnet,
  client: publicClient,
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount,
  sessionKeySigner,
  type: "ecdsa",
});

// Use this to get the session key to send transactions.

The Bundler URL above is a public endpoint. Please do not use it in production as you will likely be rate-limited. Consider using Pimlico's Bundler, Biconomy's Bundler, or another Bundler service.


Policies

Policies define the conditions under which a session key can sign UserOps. See Policies for detailed policy builders and examples.

ZeroDev exposes several policy types:

  • Sudo policy: full permissions, equivalent to the primary signer.
  • Call policy: restrict calls to specific contracts, functions, and parameters.
  • Gas policy: cap total gas usage for the session key.
  • Signature policy: limit what messages can be signed.
  • Rate limit policy: bound how frequently UserOps can be sent.
  • Timestamp policy: constrain when the key is valid (time windows).

Parameters

type

  • Value: "ecdsa"
index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa", 
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey,
  signer,
});

accountType

  • Value: "ecdsa"
index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa", 
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey,
  signer,
});

clients

  • Type: Client[]
  • Provide one public client per chain. For single-chain usage, pass a single client.
index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient], 
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey,
  signer,
});

signer

  • Type: Signer
index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey,
  signer, 
});

sessionPrivateKey

  • Type: Hex
  • The private key used by the session key signer.
index.ts
import { generatePrivateKey } from "viem/accounts";

const sessionPrivateKey = generatePrivateKey();

const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey, 
  signer,
});

policies

index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [/* ... */], 
  sessionPrivateKey,
  signer,
});

entrypointVersion

  • Type: EntrypointVersion => "0.6" | "0.7" | "0.8" | "0.9"
index.ts
import { EntryPointVersion } from "viem/account-abstraction"; 
type EntryPointVersion = "0.6" | "0.7" | "0.8" | "0.9"
const = await createSessionKey({ : "ecdsa", : "ecdsa", : [publicClient], : "0.7", : "0.3.2", : [], , , });

kernelVersion

  • Type: KernelVersion => "0.0.2" | "0.2.2" | "0.2.3" | "0.2.4" | "0.3.1" | "0.3.2" | "0.3.3"

Note: Kernel 0.2.x supports only Entrypoint 0.6. For Kernel 0.3.x, you can use Entrypoint 0.7 or 0.8.

index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2", 
  policies: [],
  sessionPrivateKey,
  signer,
});

index

index.ts
const sessionKey = await createSessionKey({
  type: "ecdsa",
  accountType: "ecdsa",
  clients: [publicClient],
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  policies: [],
  sessionPrivateKey,
  signer,
  index: 0n, 
});

serializedAccount

  • Type: string
  • Use the serialized account returned by createSessionKey.
index.ts
const serializedAccount = sessionKey.serializedAccounts[0]
  ?.serializedAccount as string;

const sessionKeyClient = await createSessionKeyClient({
  type: "ecdsa",
  client: publicClient,
  chain: mainnet,
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount, 
  sessionKeySigner,
});

sessionKeySigner

  • Type: Signer
index.ts
import { privateKeyToAccount } from "viem/accounts";

const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);

const sessionKeyClient = await createSessionKeyClient({
  type: "ecdsa",
  client: publicClient,
  chain: mainnet,
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount,
  sessionKeySigner, 
});

client

  • Type: Client<HttpTransport, Chain, JsonRpcAccount | LocalAccount | undefined>
index.ts
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";

export const publicClient = createPublicClient({
  chain: mainnet,
  transport: http(),
});

bundlerTransport

  • Type: Transport
index.ts
const sessionKeyClient = await createSessionKeyClient({
  type: "ecdsa",
  client: publicClient,
  chain: mainnet,
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount,
  sessionKeySigner,
});

chain

  • Type: Chain
index.ts
import { mainnet } from "viem/chains";

paymaster

  • Type: PaymasterClient
index.ts
import { createPaymasterClient } from "viem/account-abstraction"; 
import { createSessionKeyClient } from "@namera-ai/sdk/session-key";

const paymaster = createPaymasterClient({ 
  transport: http("ZERO_DEV_PAYMASTER_URL"), 
}); 

const sessionKeyClient = await createSessionKeyClient({
  type: "ecdsa",
  client: publicClient,
  chain: mainnet,
  bundlerTransport: http("https://public.pimlico.io/v2/1/rpc"), // Public Pimlico RPC
  entrypointVersion: "0.7",
  kernelVersion: "0.3.2",
  serializedAccount,
  sessionKeySigner,
  paymaster: paymasterClient, 
});