Type/to search
Built-in Functions
Structures
Built-in Variables and Constants
Conventions
Exchanges
Capability Matrix
Centralized Exchanges
Decentralized Exchanges (DEX)
Prediction Markets
Securities and Futures
On-chain & Custom

Cross-chain bridge (Across, Stargate, CCTP and others aggregated by LI.FI): lists the supported chains and tokens, quotes and simulates, moves tokens from this exchange object's chain to another EVM chain or Solana, and tracks delivery.

exchange.IO(k)
exchange.IO(k, chain)
exchange.IO(k, params)
exchange.IO(k, params, stateOverride)
exchange.IO(k, txHash, options)
exchange.IO(k, key)

Examples

  • Quote and simulate bridging 0.01 ETH from this chain to Arbitrum (read-only, costs nothing).

    javascript
    function main() { var params = {toChain: "arb", fromToken: "ETH", toToken: "ETH", amount: 0.01} var q = exchange.IO("bridge.quote", params) if (!q) { Log("Quote failed:", GetLastError()) return } Log("Via", q.toolName, "to", q.toChainName, "expected", q.toAmount, "at least", q.toAmountMin, "in about", q.executionDuration, "s") q.feeCosts.forEach(function (f) { Log("Fee:", f.name, f.amount, f.token, f.included ? "included in the quote" : "paid on top") }) // when the wallet balance is short, give it a temporary 100 ETH for the simulation var ov = {} ov[exchange.IO("address")] = {balance: "0x56bc75e2d63100000"} var s = exchange.IO("bridge.simulate", q, ov) Log(s ? "Simulation passed, calling " + s.to : "Simulation failed: " + GetLastError()) }
  • The complete flow: quote → simulate → send → poll the progress every 20 seconds until delivered.

    javascript
    function main() { // bridge 20 USDC from this chain to this wallet on Arbitrum var params = {toChain: "arb", fromToken: "USDC", toToken: "USDC", amount: 20} var q = exchange.IO("bridge.quote", params) if (!q || !exchange.IO("bridge.simulate", q)) { Log("Quote or simulation failed:", GetLastError()) return } var r = exchange.IO("bridge.send", q) if (!r) { Log("Send failed:", GetLastError()) return } Log("Source transaction", r.txHash, "via", r.tool) while (true) { Sleep(20000) var st = exchange.IO("bridge.status", r.txHash, {toChain: "arb", bridge: r.tool}) if (!st) { continue } Log(st.status, st.substatus || "") if (st.status == "DONE") { Log("Received", st.receiving.amount, st.receiving.token.symbol, st.receiving.txLink) break } if (st.status == "FAILED" || st.status == "INVALID") { Log("Bridge failed:", st.substatusMessage) break } } }
  • List the supported chains and quote a transfer to Solana.

    javascript
    function main() { var chains = exchange.IO("bridge.chains") Log(chains.length, "chains supported, such as", chains[0].name, chains[0].key) // a Solana destination needs toAddress (a Solana address) var q = exchange.IO("bridge.quote", {toChain: "Solana", fromToken: "USDC", toToken: "USDC", amount: 50, toAddress: "YOUR_SOLANA_ADDRESS", order: "CHEAPEST"}) Log(q ? [q.toolName, q.toAmount, q.toAmountMin] : GetLastError()) }

Returns

TypeDescription

object / array / bool / null value

Depends on the command: bridge.chains and bridge.tokens return arrays, bridge.apiKey whether a key is set, the others objects; see the remarks for the fields. Null on errors (bad parameters, short balance, rate limits rate limited (HTTP 429 …) and so on), with the reason in GetLastError().

Arguments

NameTypeRequiredDescription

k

string

Yes

The command: bridge.chains, bridge.tokens, bridge.quote, bridge.simulate, bridge.send, bridge.status or bridge.apiKey; see the remarks for their arguments.

chain

string / number

No

bridge.tokens: chain ID, LI.FI chain key or chain name; this chain when omitted.

params

object

No

bridge.quote, bridge.simulate, bridge.send: the bridge parameters {toChain, fromToken, toToken, amount, ...}, or a bridge.quote result; see the remarks.

stateOverride

object

No

bridge.simulate: state override for eth_call, to give the wallet a temporary balance.

txHash

string

No

bridge.status: the source-chain transaction hash returned by bridge.send.

options

object

No

bridge.status: {toChain, bridge} to speed up the lookup.

key

string

No

bridge.apiKey: the LI.FI API key; "" clears it.

See Also

Remarks

The commands:

CommandArgumentsDescription and result
bridge.chainsnoneChains LI.FI supports (EVM chains and Solana), cached for an hour: an array of {id, key, name, chainType, nativeToken}, chainType being EVM or SVM
bridge.tokens[chain]Tokens LI.FI knows on a chain (this chain by default), cached for an hour: an array of {symbol, address, decimals, name, priceUSD}
bridge.quoteparamsA bridge quote (read-only); fields below
bridge.simulateparams or a quote [, stateOverride]Re-quotes and runs LI.FI's transaction with eth_call, without signing or broadcasting
bridge.sendparams or a quoteRe-quotes, approves, simulates, then signs and broadcasts; waits for the source-chain broadcast only, not for delivery
bridge.statustxHash[, {toChain, bridge}]Bridge progress
bridge.apiKey[key]Sets the LI.FI API key (for this exchange object only, never echoed); "" clears it and no argument queries; returns whether a key is set

Keys of params (unknown keys are errors):

KeyDescription
toChainDestination chain: a chain ID (such as 42161), a LI.FI chain key (such as arb) or a chain name (such as Arbitrum or Solana)
fromTokenToken on this chain: a name in the token table (such as USDC or ETH) or a contract address
toTokenToken on the destination chain: a name or address, resolved by LI.FI to its canonical token (USDC on Arbitrum is native USDC, not USDC.e)
amountAmount of fromToken in token units; digits beyond the token's decimals are dropped
toAddressRecipient; this wallet by default for an EVM destination, required (a Solana address) for Solana
slippageSlippage; the exchange.IO("slippage") value by default
orderCHEAPEST or FASTEST
allowBridges, denyBridgesBridges to use only or to avoid (LI.FI bridge names, an array or comma-separated)

A quote is {tool, toolName, fromChain, toChain, toChainName, fromToken, toToken, fromAmount, toAmount, toAmountMin, fromAmountRaw, toAmountRaw, toAmountMinRaw, fromAmountUSD, toAmountUSD, slippage, toAddress, feeCosts, gasCosts, executionDuration, approvalAddress, steps, transactionId, request}: tool is the chosen bridge; amounts are in token units (*Raw in the smallest unit); toAmountMin is the amount guaranteed after slippage; feeCosts is [{name, amount, token, amountUSD, percentage, included}] (fees with included false are paid on top); gasCosts estimates source-chain gas; executionDuration is the expected time in seconds; approvalAddress is the contract to approve (null for the native coin); steps lists the steps (cross bridges, swap swaps); request echoes the parameters. A bridge.simulate result also has simulated (true), to, value and walletBalance, plus allowanceOverride when an allowance was supplied.

bridge.simulate: a short token allowance is supplied as unlimited through a state override (as in exchange.IO("simulate", ...)); balances are not, so when bridging the native coin give the wallet a balance in stateOverride. A failure caused by a short balance reports the wallet balance.

bridge.send steps: re-quote → check the balance → approve LI.FI's approvalAddress when the token allowance is short (following exchange.IO("approve") exact/max, resetting USDT-like tokens to zero first, waiting for the approval to be mined and re-quoting after it) → simulate with eth_call → sign and broadcast. The gas limit is the larger of the estimate × gasMultiplier and LI.FI's suggestion. It returns {txHash, tool, fromChain, toChain, toChainName, fromToken, toToken, fromAmount, toAmount, toAmountMin, toAddress, value, transactionId}, txHash being the source-chain transaction, whose receipt exchange.IO("receipt", ...) returns. Given a quote it re-quotes from its request; the new quote applies and toAmountMin is enforced on chain.

bridge.status returns {status, substatus, substatusMessage, tool, sending, receiving, fromAddress, toAddress, explorer, bridgeExplorer}: status is NOT_FOUND, INVALID, PENDING, DONE or FAILED; when DONE, substatus is COMPLETED (delivered as quoted), PARTIAL (a different token arrived) or REFUNDED (returned to the source chain); sending and receiving are {txHash, txLink, chainId, amount, amountRaw, token, timestamp}, receiving being what actually arrived. Right after broadcasting LI.FI may not have indexed it yet and returns NOT_FOUND; keep polling (every 10 to 30 seconds); toChain and bridge (the tool of the send result) in options speed up the lookup.

Bridging is asynchronous: delivery takes seconds to tens of minutes (see executionDuration) and must be confirmed by polling bridge.status; cross-VM transfers (EVM↔Solana) require toAddress, and funds sent to a wrong address cannot be recovered; the destination wallet needs gas to use what arrives. Without an API key LI.FI limits by outgoing IP (/quote 75 times per 2 hours, used once each by bridge.quote, bridge.simulate and bridge.send), shared by the strategies on a docker; with a key the limit is 100 per minute. Test with a small amount first.