Public Relayer
Public Relayer: Permission Context
Format signed EIP-7710 delegations for the relayer permissionContext field.
What permissionContext is
Each entry in transactions[].permissionContext is a signed delegation object in the relayer's JSON format. The relayer uses this to redeem your user's permission on-chain.
This is the most common first-integration mistake: the relayer expects **structured JSON delegation objects**, not ABI-encoded hex from encodeDelegations().
Use toRelayerJson(), not encodeDelegations()
encodeDelegations()produces ABI hex for on-chain redemption contracts — do **not** pass this to the relayer.- Use a
toRelayerJson()helper that convertsbigintvalues to0x-prefixed hex andUint8Arrayvalues withbytesToHex. - See
/examples/relayer-first-json-rpc-call.tsfor a working implementation.
Required delegation fields
delegate— must equaltargetAddressfromrelayer_getCapabilitiesfor the chain. Mismatch causes silent redemption failure.delegator— the smart account address (typically the user's EIP-7702 upgraded EOA).authority— parent delegation hash, or0x000…000for a root delegation.caveats— scope enforcers (amount limits, function selectors, expiry).salt— fresh random 32-byte hex per delegation (never reuse).signature— hex signature fromsmartAccount.signDelegation().
Minimal permissionContext shape
Single delegation in send payload
"permissionContext": [{
"delegate": "<targetAddress from relayer_getCapabilities>",
"delegator": "<smart account address>",
"authority": "0x0000000000000000000000000000000000000000000000000000000000000000",
"caveats": [],
"salt": "<fresh 32-byte hex>",
"signature": "<hex>"
}]When creating the delegation with @metamask/smart-accounts-kit, set to: targetAddress in createDelegation(). The leaf delegate field in the signed output must match that address.
Protect reusable delegations with delegationSecret
Delegations are designed to be reusable on-chain. After a transaction is mined, the signed delegation remains visible in chain data. Without protection, a third party could copy that delegation and submit a new relayer request that spends the same permission maliciously — especially when caveats are broad.
Pass an optional top-level delegationSecret on relayer_send7710Transaction and relayer_send7710TransactionMultichain send params (omit on estimate). It is **not** part of the delegation signature and never appears on-chain.
Send param (same secret on every submission)
"delegationSecret": "ChooseYourOwnSecretValueAndReuseItButDon'tRevealIt"- Pick one app-level secret (10–1024 characters), unrelated to delegation fields. Reuse the same value for every submission from your integration — not one secret per delegation.
- On the first send with a given delegation + secret, the relayer stores both hashes. Later sends with the same delegation succeed only when the secret matches.
- If the delegation is already bound and the secret does not match, the relayer rejects the request (
4216Delegation Secret Mismatch). - If you omit
delegationSecret, unbound delegations are accepted; delegations already bound to a secret are rejected until you supply the matching secret. - Tightly scoped delegations (narrow caveats, short expiry) reduce replay risk, but
delegationSecretis still recommended for open or long-lived permissions.