Minimum-input quotes
Run your own swap or other origin-chain action first, then bridge whatever it produced.
Use a minimum-input quote when your own contract does something on the
origin chain before the funds reach Across: a swap, a vault withdrawal, an
unwrap, or any other call. You rarely know the exact amount that action will
produce, so instead of a fixed origin.amount you quote on a floor,
origin.minInputAmount. Your contract then deposits whatever its action
produced, as long as it meets the floor, and Across bridges all of it.
Activated on request. Minimum-input quotes need the min-input-quote
permission. Contact Across to activate it for your integration, then
select Minimum-input quote when you create a key in the
integrator portal. Without it, the quote returns
403 permission.not_entitled.
How it works
- You request a quote with
origin.minInputAmount. It is priced on that floor. - In one transaction, your contract runs its own actions, approves Across to take the funds, and sends the deposit transaction from the quote.
- Across bridges the whole deposit. The guaranteed output, the fees and your app fee scale with the amount actually deposited.
- You track the transfer like any other.
Quote on the floor
Send origin.minInputAmount in place of origin.amount. Set depositor
to the address that will send the deposit, usually your contract. A
refund on the origin chain is paid to it.
const BASE_URL = "https://api.across.to";
const API_KEY = process.env.ACROSS_API_KEY;
const res = await fetch(`${BASE_URL}/v1/quotes`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
origin: {
token: { chainId: 42161, address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831" },
minInputAmount: "100000000", // at least 100 USDC will come out of your swap
depositor: "0xYourContractAddress",
},
destination: {
token: { chainId: 8453, address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
recipient: "0xUserWalletAddress",
},
amountType: "exact_input",
}),
});
const quote = await res.json();The response echoes the floor as origin.minAmount. Every amount and fee
on the quote, including destination.minAmount, is for a deposit of
exactly the floor.
Read the two actions
nextActions holds two steps, and no submit_execution:
| Action | What it is |
|---|---|
approve_token (id: "approval") | The ERC-20 approval for spender |
send_transaction (id: "prefunded-store") | The deposit: send data to to on the origin chain |
The deposit transaction completes the order on chain. Across picks it up from there, so there is nothing to submit to the executions endpoint.
For a native-token origin, send the deposit as the transaction value,
at least minAmount.
Deposit from your contract
Run your action, approve what it produced, and send the deposit transaction, all in the same transaction:
uint256 produced = _yourOriginAction(); // swap, withdraw, unwrap, …
IERC20(token).approve(spender, produced); // `spender` from the approval action
(bool ok, ) = depositTo.call(depositData); // `to` and `data` from the deposit action
require(ok, "Across deposit failed");The deposit must land before the quote's originValidUntil.
The deposit takes everything it is allowed to. It pulls the
caller's whole balance of the token, up to the allowance. The quote's
approval action asks for an unlimited allowance, so a contract that
holds other funds, or a wallet that follows the action as-is, would
deposit all of it. Approve only the amount you mean to deposit, from a
contract that holds only this user's funds. Don't hand this flow to end
users' wallets.
For the same reason, authorizationPolicy.approvalAmount: "exact" is
rejected on these quotes: an exact approval of the floor could not cover
a larger deposit. Set the allowance from your contract instead.
Track it
Use the quote's orderId with
GET /v1/transfers/{orderId},
or receive updates through webhooks, exactly as
in the Quickstart.
Depositing more than the floor
- The whole deposit is bridged. Relayers compete on the amount actually deposited, not the floor.
- The guaranteed output scales with it. Depositing 2% more than the floor raises the guaranteed minimum output by 2%.
- Your app fee is sized on the actual deposit too.
- With
destinationActions, steps that setpopulateDynamically: trueuse everything that arrived. On steps with a fixed amount, the surplus goes todestination.refundAddress, or to the recipient if you did not set one.
A deposit below the floor reverts, so nothing moves. There is no cap above the floor. A deposit far above it is auctioned at its real size, and if no relayer fills it, it is refunded like any other transfer.
Limits
- Gasful,
exact_inputonly. Your contract sends the deposit and pays its gas, through the approval path. If you setauthorizationPolicy.allowedTypes, it must includeapproval. - EVM origins, crosschain only. Not for same-chain swaps, and not from Solana, Tron or HyperCore.
- Not combinable with
origin.amount,originAction,attestationorauthorizationPolicy.approvalAmount: "exact".