> For the complete documentation index, see [llms.txt](https://docs.trover.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trover.tech/engineering/relay-bridging.md).

# Relay cross-chain bridging

## RPC configuration

Balance reads run through the backend so provider keys never enter the browser bundle. Configure a chain-ID-to-URL map on the API server; omitted chains fall back to Relay's current public RPC metadata:

```dotenv
RELAY_RPC_URLS_JSON={"1":"https://ethereum-rpc.example","10":"https://optimism-rpc.example","56":"https://bnb-rpc.example","137":"https://polygon-rpc.example","42161":"https://arbitrum-rpc.example","43114":"https://avalanche-rpc.example","8453":"https://base-rpc.example","4663":"https://robinhood-rpc.example"}
```

This variable is backend-only. Do not create a `NEXT_PUBLIC_` copy and do not add private RPC URLs to Vercel.

## Behavior

Relay bridging is available through signed X mentions, DMs, the authenticated API, and `/bridge`. Deterministic commands take priority over stock-token trades whenever `bridge` is present. Examples:

```
bridge 0.05 eth from robinhood to base
bridge 100 usdg from robinhood to ethereum as usdc
bridge 50 usdc from base to robinhood recipient 0x...
bridge 0.1 eth to arbitrum refund to 0x...
```

The deterministic parser owns amounts, addresses, featured-chain aliases, and obvious modifiers. Structured OpenAI extraction is used only when deterministic parsing cannot understand a natural-language bridge request. Its output is revalidated by the same strict domain schema and never supplies transaction calldata.

`TradingWallet.chainId=4663` remains the home/linking chain. Its EVM address can be used on another live Relay EVM chain. Solana, Bitcoin, Tron, lagging/disabled chains, and non-EVM routes are rejected. Relay chain and currency metadata remain authoritative; the first selector group is Ethereum, Robinhood Chain, Base, Arbitrum, Optimism, Polygon, BNB Chain, and Avalanche.

Address resolution is deterministic:

1. Per-request `recipient` or `refundTo`
2. Saved preference for the destination recipient or origin refund chain
3. Linked canonical wallet address

Symbols must resolve uniquely on their chain. Use a token contract address when a symbol is ambiguous. Decimal strings are converted with the resolved currency decimals and are never passed through JavaScript floating-point math.

### Degen 2 Stable

`/bridge` includes an advanced **DEGEN 2 STABLE** provider mode. It keeps the selected source chain and source currency, pins the destination to Stable (chain `988`) and its canonical USDT0 currency, and requests a Relay exact-input route. When Relay has liquidity, that single route performs any needed source-side conversion, the bridge, and final Stable settlement; users do not need to manually swap before bridging. The normal **Relay** mode remains available for arbitrary destination routes, and **direct LayerZero** remains available for the verified Stable-USDT0 OFT routes that are exposed by the on-chain peer check.

## Execution

RelayKit's official `@relayprotocol/relay-sdk` is the primary quote and connected-wallet execution layer. The worker stores the SDK quote, fees, expected output, impact, estimate, request ID, and each ordered step before execution. It validates that transaction `from` is the linked wallet and `chainId` is the requested origin. Delegated Privy wallets execute server-side with CAIP-2 `eip155:<chainId>` transaction calls, EIP-191 message signing, and EIP-712 typed-data signing while retaining the persisted idempotency boundary. External wallets execute the SDK's ordered steps through an adapted viem wallet; the API receives only hashes and reconciles status authoritatively.

The SDK is a compatibility and execution layer over Relay's hosted protocol services, not an offline bridge. Chain/currency discovery, status reconciliation, and provisioned webhooks still use Relay endpoints where the SDK has no equivalent action. The application validates every response locally and keeps polling fallback enabled.

Every step result is persisted before the next step. A retry reuses the stored quote; an explicit requote is rejected after any step has been submitted. Ambiguous Privy submission becomes `uncertain` and is reconciled by provider reference, transaction hash, and Relay request ID instead of rebroadcasting.

Relay status is polled until `success`, `refund`, `failure`, or the configured timeout. Webhooks reduce latency but do not replace polling. HMAC verification uses `HMAC-SHA256(apiKey, timestamp + "." + rawBody)`, a five-minute timestamp window, and constant-time comparison. Duplicate lifecycle events are keyed by event name, event timestamp, request ID, and status.

## API and CLI

User routes require a linked Privy trading profile except chain/currency/settings discovery:

```
GET  /v1/bridges/chains
GET  /v1/bridges/currencies?chainId=8453
POST /v1/bridges/intents
GET  /v1/bridges/intents
GET  /v1/bridges/intents/:id
GET  /v1/bridges/intents/:id/sdk-quote
POST /v1/bridges/intents/:id/requote
POST /v1/bridges/intents/:id/step-results
POST /v1/bridges/intents/:id/sdk-result
PUT  /v1/bridges/preferences/:chainId
DELETE /v1/bridges/preferences/:chainId
POST /v1/relay/webhook
```

Operator examples:

```bash
pnpm admin -- bridges
pnpm admin -- bridge INTENT_ID
pnpm admin -- bridge-retry INTENT_ID
pnpm admin -- bridge-disable INTENT_ID
pnpm admin -- relay-chain 8453 false
```

Every operator mutation is API-key protected and audited. Environment flags are hard stops; database/profile settings cannot enable a route prohibited by the environment allowlist/denylist.

## Provider setup

Request separate Relay API keys for local, staging, and production. Store the key only in the API/worker secret store as `RELAY_API_KEY`; it is sent to Relay as `x-api-key`. Ask Relay to provision `https://<api-host>/v1/relay/webhook` for that key. Keep polling enabled because webhook configuration and delivery are external dependencies.

Docker integration tests set `RELAY_API_BASE_URL=http://relay-mock:4010` and force `RELAY_DRY_RUN=true`. Production defaults should be reviewed explicitly: `RELAY_DRY_RUN=false` permits execution when the wallet and profile permit it, while `ENABLE_RELAY_BRIDGING=false` is the global hard stop.

## Recovery and shutdown

* Emergency stop: set `ENABLE_RELAY_BRIDGING=false` and restart API/worker. To stop only social commands, set `ENABLE_X_RELAY_BRIDGING=false`.
* Route shutdown: add the chain to `RELAY_DENIED_CHAIN_IDS`, or use `relay-chain CHAIN_ID false` for an operator stop. The environment denylist always wins.
* Stuck request: inspect the intent and Relay request ID, then query `/intents/status/v3`. Retry reconciliation; do not requote or rebroadcast after any submitted step.
* Refund: inspect `refundTo`, the origin preference, Relay status payload, origin transaction, and refund reason. A refund is terminal and is not auto-retried.
* Preference recovery: delete the affected per-chain preference so the linked wallet becomes the default again.
* Key rotation: create and provision the replacement key/webhook, roll API and worker together, verify a signed dry-run event, then revoke the old key.

Relay references: [SDK installation](https://docs.relay.link/references/relay-kit/sdk/installation), [SDK adapters](https://docs.relay.link/references/relay-kit/sdk/adapters), [SDK source](https://github.com/relayprotocol/relay-kit/tree/main/packages/sdk), [API overview](https://docs.relay.link/references/api/overview), [webhooks](https://docs.relay.link/references/api/api_guides/webhooks), and [testnet guidance](https://docs.relay.link/references/api/api_guides/testnet).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.trover.tech/engineering/relay-bridging.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
