Skip to main content
Cross-chain permits let you define the scope of the cross-chain bridging allowed by a session. You set them at the session level via crossChainPermits, not per function. Each entry whitelists a source/destination pair and the limits the session has to stay within.

Basic usage

Restrict a session to only bridge USDC from Base to Arbitrum:
const session = toSession({
  chain: base,
  owners: {
    type: 'ecdsa',
    accounts: [sessionOwnerAccount],
  },
  crossChainPermits: [
    {
      from: [{ chain: base, token: 'USDC' }],
      to: [{ chain: arbitrum, token: 'USDC' }],
    },
  ],
})
A token can be a symbol (resolved to the per-chain address) or an explicit address. Pass a single leg or an array, and omit a side entirely to leave it unrestricted — the settlement-layer allowlist, deadlines, and recipient rules still apply.
FieldDescription
fromSource chain + token (+ optional maxAmount cap). Omit for no source-token restriction.
toDestination chain + token (+ optional recipient pin). Omit for no destination-token restriction.

Guardrails

Tighten a permit with optional bounds:
crossChainPermits: [
  {
    from: [{ chain: base, token: 'USDC', maxAmount: parseUnits('100', 6) }],
    to: [{ chain: arbitrum, token: 'USDC' }],
    validAfter: new Date('2026-01-01'),
    validUntil: new Date('2027-01-01'),
    fillDeadline: [{ chain: arbitrum, max: new Date('2027-01-01') }],
  },
]
  • maxAmount on a source leg caps how much of that token the session can pull (a spending limit).
  • validAfter / validUntil bound the permit deadline. Both accept a Date.
  • fillDeadline bounds the fill window per destination chain.

Recipient safety

By default a cross-chain permit enforces bridge-to-self on-chain: the destination recipient must be the smart account itself. This stops a leaked session key from routing funds to an attacker-controlled address. Opt out explicitly only when you need to bridge to a different recipient:
crossChainPermits: [
  {
    from: [{ chain: base, token: 'USDC' }],
    to: [{ chain: arbitrum, token: 'USDC', recipient: payoutAddress }],
    allowRecipientNotAccount: true,
  },
]

Settlement layers

A permit allows any supported settlement layer by default. Pass settlementLayers to narrow it to a subset:
crossChainPermits: [
  {
    from: [{ chain: base, token: 'USDC' }],
    to: [{ chain: arbitrum, token: 'USDC' }],
    settlementLayers: ['ECO'],
  },
]