crossChainPermits, not per function.
A session holding a permit is scoped: the session key can run only the calls its settlement routes need, funded only from the permit’s from tokens. It has no wildcard fallback unless you opt in with fallback.
A permit restricts bridging authority; it does not enable the session on
another chain. For a transaction that uses the account on several chains, also
configure Multi-chain
sessions.
Basic usage
Restrict a session to bridging at most 100 USDC from Base to Arbitrum: Examples on this page use@rhinestone/sdk, where rhinestone is the RhinestoneSDK instance from Create a session with a custom setup.
Pass each token’s address on its own chain. Without
fallback, a Permit2-layer permit needs a from token on the session’s chain. Without account, a permit that delivers to the account and can settle through CCTP is refused with RECIPIENT_NEEDS_ACCOUNT.
Create permit sessions with rhinestone.createSession. It reads the settlement addresses the Orchestrator serves, which the IntentExecutor layers pin. Run rhinestone.validateSession first to list every refusal and warning.
Settlement layers
A permit settles through one or more settlement layers:
IntentExecutor layers pin their calls, including the recipient, in calldata. A session can hold one IntentExecutor-layer permit.
Default coverage
OmitsettlementLayers, or pass [] or "all", to select ACROSS plus every IntentExecutor layer among CCTP, OFT, ECO_IE and LZ that can settle the permit on the session’s chain. The SDK leaves out the rest and records them in session.settlementCoverage.dropped with the reason. session.settlementLayers lists the layers it kept.
For the basic example above, OFT and LZ are dropped because they require oneTimeUse, and ECO_IE because the permit sets no floor. Treat this as example output: coverage resolves against the served catalog and the clock when you create the session, so inspect settlementCoverage rather than assuming a route is available, and store the created session instead of rebuilding it from the definition.
SAME_CHAIN_IE is never selected by default. If no layer qualifies, the session is refused with NO_LAYER_CAN_SETTLE.
Explicit layers
Name layers to make the list strict. Every named layer must be able to settle the permit, or the session is refused with that layer’s reason. The order does not matter:SAME_CHAIN_IEmust be the only layer.OFTandLZcannot be combined, and each requiresoneTimeUse(LAYER_REQUIRES_ONE_TIME_USE).- IntentExecutor layers need named
tochains. ACROSSis the only Permit2 layer you can name withoutfallback.
settlementLayers filter can only narrow the session’s layers.
Spending budgets
maxAmount on a from leg caps what the session can move from that token on its chain, across every route the permit settles through:
- With
oneTimeUse, it caps one settlement. - Without it, it is a lifetime total shared by every intent the session signs, not a per-intent cap.
maxAmount caps the approvals the session makes. It does not count allowances the account already holds, such as one the owner gave Permit2 or a bridge, or one another session left. Those remain spendable by the session’s routes, so revoke them first if maxAmount must be the most the session can move. allowFees calls have separate caps.
Set maxAmount on each from leg on the session’s chain. When ACROSS sits beside IntentExecutor layers and a leg has no maxAmount, nothing caps what the ACROSS route moves for it, and validateSession warns with UNCAPPED_ACROSS_ROUTE.
Re-enabling a session that is already enabled resets its lifetime budget, so getSessionDetails refuses it by default. See Re-enable a session with a lifetime budget.
A reusable (no oneTimeUse) scoped ACROSS session needs the Permit2SenderPolicy on the session’s chain. On chains without it, such as Avalanche, the session is refused with PERMIT2_ROUTE_NEEDS_BOUND. Use oneTimeUse there.
Time windows
Bound the permit withvalidAfter and validUntil, and bound the fill per destination chain with fillDeadline:
validAfter/validUntilapply to every action the permit adds. OnACROSSthey also bound the Permit2 deadline.validUntilmust be a futureDate.fillDeadlineapplies toACROSSonly.ECO_IEneeds anyvalidUntilat least 7 days ahead, and is usable only until 7 days before it.
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:ACROSS enforces the recipient in its claim policy; IntentExecutor layers pin it in calldata.
Fees and delivery floors
By default a scoped permit session settles only sponsored intents without an app fee or a user-paid protocol fee taken from thefrom token. On IntentExecutor layers it also refuses unsponsored gas. These opt-ins widen or tighten that:
An intent whose fee or gas ceiling exceeds the remaining
allowFees cap fails closed. OFT and LZ quote with about 1% slippage, so set to.minAmount to at most about 99% of the expected send.
Every layer in the permit must enforce to.minAmount. CCTP cannot, so it is refused when named and dropped by default coverage. ACROSS has no output floor. Fee and floor coverage applies only to the paths each policy enforces; it is not a universal spending bound.
Open fallback
Setfallback to give a permit session a wildcard action beside its scoped calls:
"intentExecution"also allows the calls Rhinestone’s intent-execution policy admits. Rhinestone sets that policy, and it may admit more over time."sudo"allows any call, with any arguments and native value.
session.access.kind "open", and lets intents take routes other than ACROSS and fund them from any asset. With fallback:
- Omitted layers mean
ACROSS, and"all"is refused. - Only Permit2-layer permits (
ACROSS,SAME_CHAIN) qualify. IntentExecutor layers,restrictToActions, andswapare refused withFALLBACK_NOT_APPLICABLE. - The recipient pin holds only for intents settled through
ACROSS(warningFALLBACK_RECIPIENT_PIN_ACROSS_ONLY). maxAmountrequiresoneTimeUse.
fallback just to make an incompatible scope compile. Fix the scope instead, or declare the extra actions you need.
Scoped session behavior
A scoped permit session settles cross-chain intents only, or with a swap scope, same-chain intents funded from its sell tokens. A destination call or leftover sweep on the destination chain needs the destination chain’s session to declare those actions, or to setfallback.
You can combine a permit with restrictToActions, permissions, and actions to let the same key run other explicit calls.