Relay Bridging
Playbook for bridging, swapping, and bridge+calling via Relay through OpenFinance.
Three operations, one API
| Operation | What it is |
|---|
| Swap | Same-chain token swap (origin = destination chain) |
| Bridge | Move tokens across chains (USDC on Polygon → USDC on Base) |
| Bridge+call | Bridge + execute a destination-chain tx after the bridge lands — pass the tx(s) in |
Relay picks the route automatically; you just provide the inputs.
Endpoints
All three require
. Relay aggregates liquidity across 40+
chains — you pass the chain IDs directly; the backend picks the route.
— quote only
Fetches a Relay quote for a swap, bridge, or bridge+call. Does NOT submit
any transactions. Use for preview UIs, fee estimation, or to show the user
the route before they confirm.
Request body:
json
{
"originChainId": 137,
"destinationChainId": 8453,
"originCurrency": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"destinationCurrency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000000",
"tradeType": "EXACT_INPUT",
"recipient": "...", // optional; defaults to user's dest-chain addr
"slippageTolerance": "50", // basis points, optional
"topupGas": true, // optional; forced false for Solana routes
"topupGasAmount": "100000", // USD micro-units, optional
"usePermit": false, // EIP-3009 permit for supported tokens
"txs": [{"to", "data", "value"}], // optional; for bridge+call
"appFees": [{"recipient", "fee"}] // optional
}
is server-injected from the caller's wallet based on
— do NOT pass it. The backend selects EVM or Solana address automatically.
Returns the full response:
{steps, fees, feeSponsorship}
.
is an
array of signable/submittable actions (transactions or signatures) with
embedded
endpoints for status polling.
POST /agent/relay/execute
— quote + sign + submit + poll
End-to-end flow. Same body as
. The backend:
- Fetches the quote
- Walks every :
- EVM transaction step → sends via viem
walletClient.sendTransaction
on the correct chain, waits for 1 confirmation
- Solana transaction step → compiles + ALTs into a
VersionedTransaction, has Privy sign it (), broadcasts
via our RPC with , confirms with the original
blockhash/lastValidBlockHeight
- EIP-712 signature step → signs with the user's EVM account and
POSTs the signature to the step's
- Polls with exponential backoff (1s → 10s, 5-min
cap) until terminal status
Returns
{requestId, quote, txHashes, finalStatus}
.
Use when the user confirms the quote or directly asks to bridge / swap /
execute. Solana-origin requires the user's Solana wallet to be delegated
(see
step 2).
GET /agent/relay/status?requestId=<id>
— manual status lookup
Get the current status of a Relay intent by its
. Use for
manual polling from the frontend when
wasn't awaited, or for
audit lookups.
Status values:
- — awaiting deposit confirmation
- — origin deposit confirmed, pending fill
- — deposit confirmed, awaiting destination submission
- — destination transaction submitted
- — destination fill still processing
- — successful fill on destination (terminal)
- — successfully refunded (terminal)
- — unsuccessful fill (terminal)
Response also includes
(free-form text),
,
,
(ms),
,
.
Required inputs
| Field | Type | Notes |
|---|
| number | Source chain |
| number | Destination chain |
| string | Token contract on origin (or for EVM native) |
| string | Token contract on destination |
| string | Smallest unit as a STRING (wei for 18-dec, = 10 USDC) |
| string | | | |
is server-injected based on
— pass the right wallet
for the origin. Solana origin → Solana address; EVM origin → EVM address.
Do not pass it yourself.
defaults to the user's address on the
destination chain.
Override explicitly if bridging to a different address.
Chain ID cheatsheet
| Chain | ID |
|---|
| Ethereum | |
| Polygon | |
| Base | |
| Optimism | |
| Arbitrum | |
| BSC | |
| Linea | |
| Blast | |
| Scroll | |
| zkSync Era | |
| Hyperliquid | |
| Solana | |
| Bitcoin | |
| Tron | |
Live list:
GET https://api.relay.link/chains
.
Treat that endpoint as source of truth for supported
origin chains.
Native-token sentinel
Use
0x0000000000000000000000000000000000000000
for the EVM native token
on any EVM chain (ETH / MATIC / BNB / etc.).
For Solana, use
So11111111111111111111111111111111111111112
for wrapped
SOL, or the SPL mint address for tokens (e.g.
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
for USDC).
Trade types
| Type | Meaning | Example |
|---|
| Send exactly , receive variable | "Bridge 10 USDC" |
| Send variable, receive exactly | "Get me exactly 1 ETH on Base" |
| Alternate routing | Rarely needed |
Most prompts are
. If user says "I want to receive X", use
.
Gas topup defaults
Backend behavior:
- EVM ↔ EVM: default, ($0.10).
Relay only applies it if the recipient needs gas.
- Any route with Solana (chainId ): forced .
- Ethereum L1 destination: bump to ($0.50).
Override per-call via body fields
and
.
Solana-origin example
Bridge the user's USDC from Solana back to USDC.e on Polygon:
json
{
"originChainId": 792703809,
"destinationChainId": 137,
"originCurrency": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"destinationCurrency": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"amount": "1000000",
"tradeType": "EXACT_INPUT"
}
auto-fills as the user's Solana address;
auto-fills as
their EVM address.
Requires Solana wallet delegation (see
). Without it, execute fails with 412.
Bridge+call example
Bridge USDC.e Polygon → USDC Base, then call a contract on Base:
json
{
"originChainId": 137,
"destinationChainId": 8453,
"originCurrency": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"destinationCurrency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000000",
"tradeType": "EXACT_INPUT",
"txs": [
{ "to": "0x…target…", "data": "0x…calldata…", "value": "0" }
]
}
Status values
- Terminal success: ,
- Terminal failure:
- In-flight: , , , ,
If
returns non-terminal
, keep polling
with the
.
Don't
- Don't use human-readable amounts. = 1 USDC, not .
- Don't pass or — server injects.
- Don't retry a without checking — refund may be automatic
( will follow), or the route may be unsupported.
- Don't assume Solana delegation carries over from EVM. Each chain type
delegates separately in Privy.
MCP note