Bridge Quote
[Alpha Preview] Get a cross-chain bridge quote with a ready-to-sign deposit transaction. EVM, Solana, and HyperLiquid.
GET /api/2/bridge/quote returns a ready-to-sign deposit transaction plus a
intentId you’ll use to poll status. The Mobula solver detects the deposit
(flash blocks on Base, gRPC on Solana) and fills on the destination chain.
Typical end-to-end latency: ~500 ms for Base ↔ Solana, ~1–3 s elsewhere.
Query parameters
{ "error": "..." } with HTTP 200 — always check
the error key before reading data. The exceptions: a signature that fails to
recover on the commit call is HTTP 400, an unknown API key is 404, and a
prediction-persist failure is 503.
Response
intentIdis the user-facing handle, formatxxxxxxx-xxxxxxx-xxx(lowercase hex). Pass it toGET /status/:idor/status/:id/wait. There is also an on-chainbytes32intent ID emitted byMobulaBridgeon EVM deposits — both resolve in/status/:id, so use whichever you have. You must echo this exactintentIdback via theintentIdquery param when submitting the signature — the signed payload binds to it.deadlineis Unix seconds. The server rejects signed calls past this point.typedDatais the EIP-712 structured-data payload your wallet should sign (see Signed-quote flow for the full schema).signatureRequired: trueforevm:*andhl:mainnetorigins.falseforsolana:solana(the depositor-signed memo replaces the signature).prediction.persistedindicates whether the server has committed your signed intent.falseon the unsigned preview call;trueafter a successful signed call.stepslists the on-chain transactions for EVM origins:[{type:'bridge'}]for native,[{type:'approve'},{type:'bridgeToken'}]for direct-bridge tokens,[{type:'approve'},{type:'swapAndBridge'}]for other ERC-20s. Solana and HL deposits omitsteps.recommendedSlippageis the slippage % we suggest signing with — the measured price impact of the quote’s swap leg(s) (max across the origin and destination swaps;0for a direct stable transfer) plus any fee-on-transfer tax, plus a1%drift buffer, rounded up to0.01and capped at50. Native-token destinations are floored at2%(the fill is served by a market swap). Bridge fee and destination gas are not part of it — they’re already deducted from the quoted output. The solver refunds any fill below the signedminAmountOut(failure codeslippage), so a tolerance under this value is a near-guaranteed refund. If yourslippageis below it, re-quote at the recommendation before signing.feesare real, deducted amounts — there is no placeholder.bridgeFeeUsdis the Mobula protocol fee (bridgeFeeBps, currently5);destFillGasUsdis what the solver pays to fill on the destination chain;gasFeeUsdequalsdestFillGasUsd.destActivationCostUsdappears only when the destination needs a one-off account-creation cost (e.g. Solana ATA rent for a first-time recipient) — it’s omitted otherwise.integratorFeeBps/integratorFeeUsdappear only when you passfeeBps+feeWallet(see Integrator fee).totalFeeUsdisbridgeFeeUsd + gasFeeUsdplus the integrator cut when present — it does not includedestActivationCostUsd.estimatedAmountOut/estimatedAmountOutUsdare already net of every fee (activation cost included); the user additionally pays only origin-chain gas to broadcast the deposit.destinationType/originTypeare echoed back only for HyperLiquid routes (spotorperps), reflecting the venue the funds land in / are pulled from.
Integrator fee
PassfeeBps + feeWallet to take a cut on top of the Mobula protocol fee.
feeBpsis your fee in basis points — integer0–500(up to 5%). It only applies whenfeeWalletis also present.- The fee is paid in USDC on the destination chain, at fill time (not on the
origin).
feeWalletmust therefore be a valid destination-ecosystem address (0x…forevm:*/hl:mainnet, base58 forsolana:solana); a mismatch is rejected before the fee is charged. On HyperLiquid destinations a payout to an unactivated account is skipped (first receipt on an unactivated HL account costs the sender ~$1). - The cut is folded into the signed
minAmountOut, so it comes out of the bridged amount — the recipient still receives exactlyestimatedAmountOut. - When applied, the quote’s
feesobject echoesintegratorFeeBpsandintegratorFeeUsd, andtotalFeeUsdincludes it.
deposit shapes
The shape depends on originChainId. Sign and broadcast whichever one is
present.
EVM origin (deposit.evm)
- Native ETH/BNB/POL — single
bridge()call onMobulaBridge.valueis the raw amount in wei.stepshas onebridgeentry. - Direct-bridge tokens —
approvestep toMobulaBridge, thenbridgeToken().valueis"0". The set is exactly the chain’s canonical USDC (Base, BSC, Arbitrum, Polygon) — every other ERC-20, including USDbC and USDT, takes the swap-and-bridge path. Robinhood Chain has no USDC, so it’s native + swap only. - Any other ERC-20 —
approvestep toSwapBridgeHelper, thenswapAndBridge()— atomic swap to native + bridge in one TX. The embedded swap calldata is validated server-side to start with theMobulaRouter.executeRouteselector (0xa564dfa4); if it doesn’t, the quote returns"Swap quote failed: invalid calldata selector".
MobulaBridge (MobulaBridgeV2, deployed 2026-06-04) is the same proxy address
on every EVM chain:
SwapBridgeHelper (the
spender named in the approve step) — always approve the spender the step
specifies, not a hardcoded address.
Approval handling: approvalAmount is always MAX_UINT256, so a single
approve per (token, spender) is enough forever. Skip the approve step only
if the current on-chain allowance already covers amount.
Solana origin (deposit.solana)
Two shapes depending on token:
- Native SOL —
{ to, amount, memo }. Build aSystemProgram.transferforamountlamports toto(the solver address), then add a memo instruction (programMemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr) whose data is thememostring. The memo is a JSON blob the solver parses to recoverintentId,destinationChainId,recipient,destinationToken, andminAmountOut. - SPL —
{ type: "spl-transfer" | "swap-transfer", serializedTx }. The server has already built the full versioned transaction. Canonical USDC is a directspl-transfer(SPL transfer + ATA creation if missing + memo); any other SPL token isswap-transfer— an atomic swap to USDC + transfer + memo in one transaction. Either way, justVersionedTransaction.deserialize, sign, and send.
HyperLiquid origin (deposit.hl)
type follows originType: spotSend (the default, originType=spot)
carries a token field; usdSend (originType=perps, always USDC) has no
token. Submit the matching action to the solver L1 address (to from the
response — don’t hardcode it) using your HL signer.
Same-chain quotes
WhenoriginChainId === destinationChainId, the server short-circuits
into a swap-wrapper. The response is the raw Swap API response, not the
bridge shape above (no intentId, no deposit.evm/solana/hl). Approval
amounts in the response are overridden to MAX_UINT256 server-side.
Branch on the response: data.deposit present → bridge flow; otherwise →
swap flow.
Signed-quote flow
Forevm:* and hl:mainnet origins the destination token (and, for HL, the
destination address) is not committed on chain — the server holds it against
the depositor’s address until the deposit lands. Without binding that to the
depositor’s key, anyone who knows the address could overwrite it and redirect
funds to a different token. To close that hole, /quote enforces an EIP-712
signature flow.
The flow is two API calls plus one wallet signature:
- Preview call —
GET /quote?...with nosignature. Server returns the quote, the deposit calldata, and atypedDatapayload. Nothing is committed yet. - Sign — your wallet signs
typedData(e.g.eth_signTypedData_v4for injected wallets,walletClient.signTypedDatawith viem). The signer’s address must equaltypedData.message.sender. - Commit call —
GET /quote?...&signature=<sig>&intentId=<id>&deadline=<ts>&minAmountOut=<raw>with the same input params as call 1. Server reconstructs the typedData from the query params, recovers the signer, and commits your signed intent if everything lines up. Returns the same response shape withprediction.persisted: true. - Broadcast — submit
deposit.evm(ordeposit.hl) on chain.
EIP-712 schema
EIP712Domain type from types — inject it client-side
(name:string, version:string, chainId:uint256) before signing if your signer
needs it.
HyperLiquid specifics. HL signs all actions under Ethereum mainnet, so for
hl:mainnet origins typedData.domain.chainId is 1 (not 999) — switch the
wallet to chain 1 before signing. An HL bridge then needs two signatures:
(1) this EIP-712 BridgeIntent confirm, then (2) the HL transfer to the solver
(spotSend, or usdSend when originType=perps).
Failure modes on the commit call
- HTTP 400
Signature recovers to 0x…; expected sender 0x…— the signature recovered to a different address than the expected signer. Re-checktypedData.message.senderand the signer. - HTTP 400
Invalid bridge intent signature: …— the signature is malformed (recovery itself threw). - HTTP 200
{ "error": "Signature deadline has expired or is invalid" }—deadlineis pastnow. Re-quote. - HTTP 200
{ "error": "Signed-mode quote requires intentId, deadline, minAmountOut, and signature query params (echo the values returned by the unsigned call)" }— one of the four signed-mode params is missing.
Side effects
/quote commits your signed intent — bound to (sender, originChainId, destinationChainId) — only when called with a valid signature (Solana
origin: committed on every call, since the memo carries the binding). The
server uses it to resolve destinationToken, recipient, and slippage when
the deposit lands. For EVM/HL origins a deposit with no committed signature is
rejected (and refunded) — so always complete the commit call before
broadcasting.
Example
EVM origin (signed-quote flow, Base → BSC, 100 USDC → USDT):/status/:id/wait with
quote.intentId.Query Parameters
Origin chain ID (e.g., "evm:8453", "solana:solana", "hl:mainnet")
Destination chain ID (e.g., "evm:8453", "solana:solana", "hl:mainnet")
Human-readable amount of origin token to bridge (e.g., "0.1")
Recipient wallet address on the destination chain (EVM hex, Solana base58, or HL hex).
Origin token contract/mint address. Omit or pass the zero address for the native token.
Destination token contract/mint address. Omit or pass the zero address for the native token.
Slippage tolerance in percent (0-50, default: 1).
Origin-chain sender address. Required when bridging an SPL token from Solana (the wallet signing the swap+deposit TX).
Response
Bridge quote response. Either data is populated with quote + deposit instructions, or error describes why the quote could not be built.