Full API reference as one Markdown file: bridge-all.md.
Copy it, or feed it to your LLM as context for the entire bridge surface in one paste.
bridge() function that handles
every origin chain — EVM, Solana, and HyperLiquid — and the bottom of the page
calls it for several different routes you can mix and match.
The flow is: GET /quote (preview) → for evm:* and hl:mainnet origins, sign
the returned EIP-712 typedData and re-call /quote to commit the signature →
broadcast the returned deposit → long-poll GET /status/{intentId}/wait until
terminal. (Solana origins skip the signature — the depositor-signed memo carries
the binding.)
Install
bridge.ts
Copy this entire block as one file. It exports bridge(params, signers, apiKey)
which works for every supported route.
Multi-route example
This is one driver script that bridges across four different route shapes using thebridge() function above. It exercises every code path (native,
direct-bridge token with approval, swap-and-bridge, Solana, HyperLiquid).
How each route maps to a code path
The
bridge() function above auto-dispatches by inspecting quote.deposit and
quote.steps — you don’t pick the path manually.
Notes worth knowing
- No client-side sleep when polling
/status/{id}/wait. The server already blocks server-side and resolves the long-poll the instant the intent goes terminal (default 30 s window, capped 60 s). Re-firing the request immediately keeps one connection always waiting on the next state change. - Want the intermediate states?
/waitresolves once, on the terminal row. Subscribe tobridge-statusonwss://api.mobula.ioinstead when your UI needs to move throughfillingas it happens, or to follow several bridges on one connection — see Bridge Status. - Approvals are
MAX_UINT256. One approve per (token, spender) is enough forever — read the on-chainallowance(owner, spender)and skip the approve step if it’s already non-zero (or above your amount). - Stale
/waitresponses. If you start a new bridge while a previous/waitis in flight, the previous response can land after your newintentIdis active. Track the active intent on your side and discard any/waitresult that doesn’t match it. - Hyperliquid fills complete before their tx hash exists. An HL-destination
fill is final the moment the funds leave HL, but HL assigns the canonical L1
hash a moment later — so a
filledresponse can carryfillTxHash: nullwithfillTxHashPending: true. Show “complete” as soon asstatusisfilled; don’t block on the hash. Fetch the hash afterward with a second long-poll,GET /status/{id}/wait?waitForFillTxHash=true, and patch your explorer link when it lands. See Bridge Status → best practice. - No fixed per-intent cap. The old
maxTradeUsd: 400limit was removed — trade size is now bounded by the solver’s available inventory on the destination route. An intent the solver can’t source is refunded, so always handle therefundedterminal state rather than assuming a fixed ceiling. - Optional integrator fee (
feeBps+feeWallet). Pass both to skim a cut for yourself:feeBpsis your fee in basis points (0–500, i.e. up to 5%) andfeeWalletis where it’s paid. The fee is paid in USDC on the destination chain at fill time, sofeeWalletmust be a valid destination-ecosystem address (0x for EVM/HL destinations, base58 for Solana) — a mismatch is rejected. It’s already folded into the signedminAmountOut, so the recipient still receives exactlyestimatedAmountOut; the fee comes out of the bridged amount, not on top. When set, the quote’sfeesobject echoes backintegratorFeeBpsandintegratorFeeUsd. - Honor
recommendedSlippageor risk a refund. Every quote returns arecommendedSlippage(%) — the measured price impact of the quote’s swap leg(s) plus any fee-on-transfer tax plus a 1% drift buffer, with a 2% floor on native-token destinations (bridge fee and gas are already deducted from the quoted output, not part of slippage). The solver refunds any fill that lands below the signedminAmountOut(failure codeslippage), so signing with a tolerance underrecommendedSlippageis a near-guaranteed refund. Thebridge()function above passesslippage=auto, so the server applies the recommendation and builds that floor into the quote before it is signed. - Fees are real and already deducted from
estimatedAmountOut. The quote’sfeesobject breaks them down:bridgeFeeUsd(protocol fee,bridgeFeeBps, currently5),destFillGasUsd(what the solver pays to fill on the destination chain), anddestActivationCostUsd(present only when the destination needs a one-off account-creation cost — e.g. Solana ATA rent for a first-time recipient).gasFeeUsdequalsdestFillGasUsd, andtotalFeeUsdisbridgeFeeUsd + gasFeeUsd(+ the integrator cut when you set one) — activation cost is deducted from the output but not folded intototalFeeUsd.estimatedAmountOut/estimatedAmountOutUsdare net of every fee — the recipient receives exactly that. The user additionally pays only origin-chain gas to broadcast the deposit; the solver pays the destination fill gas itself. - EVM origins can skip origin gas entirely (
gasless=true). Quote withgasless=trueand Mobula broadcasts the deposit for the user and pays its gas — an EVM wallet holding zero ETH/BNB/POL can approve and bridge with one signature. The user signs the quote’sstepsas an EIP-712 batch (EIP-7702) instead of sending them, and you post that batch toPOST /executein place of thesendTransactioncalls in the file above; everything after (status polling, refunds) is unchanged. The origin gas is not free — it appears asfees.originSponsorGasUsdand is deducted from the output. Cross-chain, ERC-20-origin routes only. - Solana origins skip it too, with no extra call.
gasless=trueon asolana:solanaorigin returnsdeposit.solana.serializedTxalready signed by Mobula’s fee payer (coSigned: true, alongsidefeePayerand theblockhashthat signature covers). Deserialize, have the user’s wallet add its signature, submit to any RPC — the code path in the file above is unchanged except that you must NOT replacerecentBlockhash, which would void the co-signature. Priced the same way (fees.originSponsorGasUsd), and the transaction lives as long as its blockhash (~60s), so re-quote rather than sit on it. SPL origins only.