> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rhinestone.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Cross-chain permits

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:

```ts {7-12} theme={null}
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.

| Field  | Description                                                                                        |
| ------ | -------------------------------------------------------------------------------------------------- |
| `from` | Source chain + token (+ optional `maxAmount` cap). Omit for no source-token restriction.           |
| `to`   | Destination chain + token (+ optional `recipient` pin). Omit for no destination-token restriction. |

## Guardrails

Tighten a permit with optional bounds:

```ts {8-14} theme={null}
const session = toSession({
  chain: base,
  owners: {
    type: 'ecdsa',
    accounts: [sessionOwnerAccount],
  },
  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:

```ts {10-11} theme={null}
const session = toSession({
  chain: base,
  owners: {
    type: 'ecdsa',
    accounts: [sessionOwnerAccount],
  },
  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:

```ts {11} theme={null}
const session = toSession({
  chain: base,
  owners: {
    type: 'ecdsa',
    accounts: [sessionOwnerAccount],
  },
  crossChainPermits: [
    {
      from: [{ chain: base, token: 'USDC' }],
      to: [{ chain: arbitrum, token: 'USDC' }],
      settlementLayers: ['ECO'],
    },
  ],
})
```
