Swap
Allowance-holder swaps on BSC (56), Ethereum (1), Base (8453) and Polygon (137). The taker approves the settlement contract for the exact amount and sends the transaction from the quote.
| Endpoint | Use |
|---|---|
GET /swap/allowance-holder/price | Indicative price, no transaction. taker is optional. |
GET /swap/allowance-holder/quote | Firm quote with transaction. taker is required. |
Parameters
| Parameter | Rule |
|---|---|
chainId | Required. 56, 1, 8453 or 137. Other values: 400 CHAIN_NOT_SUPPORTED. |
sellToken, buyToken | Required. Addresses in any letter case. The native coin is 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE. |
sellAmount | Required. Base units, decimal string, above 0. |
taker | Required on quote, optional on price. With a taker, issues are filled and the wallet's on-chain fee rate is used. |
recipient | Absent, or equal to taker. Another address gives 400 RECIPIENT_NOT_SUPPORTED: the contract pays the sender. |
slippageBps | Default 100, allowed 10 to 1000. |
slippagePpm | 1,000 to 100,000, rounded down to whole bps (warning slippage_ppm_rounded when not a multiple of 100). Not together with slippageBps. |
deadlineSeconds | Seconds until the transaction deadline (expiresAt). Default 120, allowed 30 to 600. |
excludedSources | Comma-separated names from GET /sources. Unknown names are listed in issues.invalidSourcesPassed. |
gasPrice | Gas price in wei for the estimate. Default: the chain's current price. |
Integrator fee: swapFeeRecipient (one wallet, or up to 3 separated by commas) and swapFeeBps (one value per wallet, 300 in total), optionally swapFeeToken (sellToken or buyToken, default buyToken); the router pays each wallet in the same transaction and the answer lists them in fees.integratorFees. tradeSurplus*, txOrigin, sellEntireBalance and wrapUnwrapMode are accepted and ignored; buyAmount (exact-out) is not supported in v1. Unknown parameters are ignored; a repeated parameter gives 400 INPUT_INVALID.
Pairs
Each pair needs an anchor on at least one side. The other side is an anchor or a token listed by GET /tokens?chainId=.
| Chain | Anchors |
|---|---|
| BSC (56) | BNB, WBNB, USDT, USDC |
| Ethereum (1) | ETH, WETH, USDT, USDC |
| Base (8453) | ETH, WETH, USDT, USDC |
| Polygon (137) | POL, WPOL, USDT, USDC |
| Pair | Answer |
|---|---|
| Same token on both sides | 400 TOKEN_PAIR_NOT_SUPPORTED |
A token not in GET /tokens | 400 TOKEN_NOT_SUPPORTED with data.token |
| No anchor on either side | 400 TOKEN_PAIR_NOT_SUPPORTED, data.reason no_anchor |
| Native coin and its wrapped token | 400 TOKEN_PAIR_NOT_SUPPORTED, data.reason wrap_unwrap |
| A token with a transfer tax | 400 TOKEN_NOT_SUPPORTED, data.reason transfer_tax (found by the quote simulation) |
Fee
The on-chain fee is fees.qiguardFee: 0.50% (50 bps) of the trade, or the lower on-chain rate of the taker wallet when it has one. It is charged by the settlement contract in the same transaction.
| Sell | Buy | Fee taken from | Fee token |
|---|---|---|---|
| USDT | any token | the sell amount, before the swap | USDT |
| USDT | native coin | the sell amount | USDT |
| any token | USDT | the gross output | USDT |
| native coin | USDT | the gross output | USDT |
| token X (USDC and wrapped native included) | token Y (not USDT) | the gross output | Y |
| token (not USDT) | native coin | the gross output | native coin |
| native coin | token (not USDT) | the gross output | that token |
buyAmount and minBuyAmount are net: what the taker receives after the fee. The contract checks minBuyAmount against the net amount.
minBuyAmount = floor(buyAmount * (10000 - slippageBps) / 10000)
A minBuyAmount of 0 gives 400 SELL_AMOUNT_TOO_SMALL.
Approvals
allowanceTargetis the settlement contract of the chain (nullwhen selling the native coin).- When the taker's allowance is below
sellAmount, the quote setsissues.allowance = { actual, spender }. Approvespenderfor exactlysellAmount, wait for the receipt, then quote again. issues.allowance.resetRequired: true(USDT on Ethereum with a non-zero allowance): approve 0 first, then the exact amount.- When the balance is short,
issues.balance = { token, actual, expected }. - The SDK helper
approvalsForQuote(quote)returns exactly these approval transactions.
The transaction
The quote returns transaction = { to, data, value, gas, gasPrice }. Send it unchanged; use gas as the gas limit.
| Field | Meaning |
|---|---|
transaction.to | The settlement contract. |
transaction.data | marketSwap, marketSwapNativeToToken (selling the native coin) or marketSwapTokenToNative (buying the native coin), then the 18-byte Qiguard tag. |
transaction.value | sellAmount when selling the native coin, else 0. |
expiresAt | The deadline inside transaction.data (Unix seconds). The contract refuses the transaction after it. |
qiguard | function, selector, adapter, deadline and tag of the call. |
totalNetworkFee | gas x gasPrice, plus the L1 data fee on Base. |
The price endpoint returns the same object without transaction, qiguard and expiresAt, and with top-level gas and gasPrice. When no route exists, both endpoints answer 200 with only { "liquidityAvailable": false, "zid": "..." }.
Quote checks
- Two RPC operators. The quote is read on one RPC operator, then the best routes are read again on a second, independent operator at the same block. They must agree within 30 bps, else
503 RPC_UNAVAILABLE.protection.quoteIntegrityshowsrpcAgreement,maxDeviationBpsandblock. - Simulation. When the taker's balance and allowance are enough, the quote runs the exact transaction with
eth_callfrom the taker and estimates its gas (gas= estimate x 1.2).protection.simulationispassed,skipped_allowanceorskipped_balance; on the price endpoint it isnot_run. A revert gives400 SWAP_VALIDATION_FAILED(data.reasonslippageoradapter_not_allowed,data.revertfor other reverts). - Paused contract.
protection.settlementPausedreflects the livepaused()flag of the settlement contract. While it is true, price and quote answer503 SETTLEMENT_PAUSED. protection.priceBand.priceImpactBps(quote only) compares the execution price with a small reference trade on the same route.protection.mev.submissionistaker_submits: the taker sends the transaction.
Calldata tag
transaction.data ends with 18 bytes: 0x71673031 ("qg01"), the first 8 bytes of sha256 of the app id, and the first 6 bytes of the response zid. The contract ignores bytes after the call arguments. The tag attributes the trade to the app; an app can switch it off in the dashboard (app settings).
Warnings
warnings[] lists accepted parameters that changed nothing: trade_surplus_ignored, tx_origin_ignored, wrap_unwrap_mode_ignored, slippage_ppm_rounded, and secret_key_origin_header (a secret key arrived with an Origin header; send it from a server without browser headers).
This page as Markdown: swap.md. All pages for tools: llms.txt.