Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

grantSession

Grant a scoped session key for a wallet. The admin signer authorizes the session on-chain; from that point forward the session can act on the wallet within its permissions, enforced on-chain.

const session = await grantSession(wallet, admin, {
  permissions: {
    calls: [{ to: "0xUniswapRouter..." }],
    spend: [{
      limit: 100_000_000n,        // 100 USDC (6 decimals)
      period: "day",
      token: "0xUSDC...",
    }],
  },
  expiry: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60, // 7 days
});
 
// Hand `session` to whichever process runs the agent.

Keystore impact

The session's public key is written to Keystore via the Controller. From that moment, any tool reading getActiveKeys on the wallet sees this session. Reads are free and unlimited.

Parameters

function grantSession(
  wallet: Wallet,
  adminSigner: Signer,
  opts: GrantSessionOptions,
  config?: { network?: NetworkConfig; feeToken?: Address },
): Promise<Session>;
 
type GrantSessionOptions = {
  permissions: SessionPermissions;
  /** Unix epoch seconds. Most apps use Date.now()/1000 + N. */
  expiry: number;
  /** Bring your own session signer, or omit to let the SDK generate one. */
  sessionSigner?: Signer;
};

See Sessions for the full permission shape reference.

Returns

type Session = {
  walletAddress: Address;
  signer: Signer;          // session key. Agent signs with this.
  publicKey: Hex;
  permissions: SessionPermissions;
  expiry: number;
};

What lands on-chain

In a single userOp:

  1. The session's public key is registered in Keystore, making it discoverable by any tool.
  2. The session is authorized on the wallet's smart account with its permissions hash.

Both happen atomically. There is no intermediate state where one exists without the other.

Notes

  • Persist the full Session object, not just publicKey. The agent needs permissions + expiry byte-exact at execute time.
  • If you generated the session signer (omitted sessionSigner), persist session.signer securely. Losing it means the session can no longer sign.
  • permissions.calls omitted = unrestricted. Always set both calls and spend unless you specifically want an open-scope session.