Skip to main content
Permit2 is the preferred flow for swap transactions through Rialto. Contract signers can also use Permit2 when they implement EIP-1271 signature validation. For legacy integrations that cannot provide a valid Permit2 signature, Rialto also supports allowance settlement. For integration instructions, see the Taker-submitted flow in the Rialto API docs.

Contract-based executors

Most liquidation bots execute through an executor or liquidator contract. That contract may receive the seized collateral, approve a swap router, perform the swap, and then send the output to the bot, treasury, or another recipient. The example below shows allowance settlement for executors that cannot provide a valid Permit2 signature. In this flow, the quote can be executed after the contract approves the spender returned by Rialto. For allowance flow, the quote should have:
  • settlement: "allowance"
  • taker set to the account or contract that holds and pays the sell token
  • tx.to set to the active Rialto router
  • tx.data executable by the executor contract
  • tx.value set for native-token sells, or 0 for ERC20 sells
  • issues.allowance.spender set when an ERC20 approval is needed

Integration flow

  1. Detect a liquidatable position.
  2. Estimate the collateral amount to sell and the token you want to receive.
  3. Call GET /quote with the executor contract as the taker.
  4. If issues.balance is present, do not execute the liquidation.
  5. If issues.allowance is present, approve the returned spender from the executor contract for at least sell_amount, preferably within the same transaction.
  6. Execute tx.to, tx.data, and tx.value from the executor contract.
  7. Reset the token allowance to zero after execution, preferably within the same transaction.

Quote request

curl -sS 'https://rialto-trade-api.rialto.xyz/quote?sell_token=WETH&buy_token=USDG&sell_amount=0.01&taker=<executor_contract>&slippage_bps=50&chain_id=4663' \
  -H "Authorization: Bearer $RIALTO_API_KEY"
Use the executor contract as taker when the executor will hold the sell token and submit the swap call.

Response fields to use

{
  "settlement": "allowance",
  "sell_token": "<sell_token_address>",
  "buy_token": "<buy_token_address>",
  "sell_amount": "10000000000000000",
  "buy_amount": "19800022",
  "min_buy_amount": "19701021",
  "issues": {
    "allowance": {
      "actual": "0",
      "spender": "<rialto_router_or_spender>"
    },
    "balance": null,
    "simulationIncomplete": false
  },
  "tx": {
    "to": "<rialto_router_address>",
    "data": "0x...",
    "value": "0",
    "estimated_gas": 226046
  }
}
For allowance settlement, use issues.allowance.spender as the approval target. Use tx.to, tx.data, and tx.value as the swap call. Do not recompute the route, fee logic, slippage math, or calldata. The returned transaction is the integration boundary.

Executor sketch

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract LiquidationExecutor {
    address public owner;

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    constructor(address _owner) {
        owner = _owner;
    }

    function executeRialtoSwap(
        address sellToken,
        address spender,
        uint256 sellAmount,
        address rialtoRouter,
        bytes calldata rialtoData,
        uint256 value
    ) external payable onlyOwner {
        if (sellToken != address(0)) {
            IERC20(sellToken).approve(spender, sellAmount);
        }

        (bool ok, bytes memory result) = rialtoRouter.call{value: value}(rialtoData);
        if (!ok) {
            assembly {
                revert(add(result, 32), mload(result))
            }
        }

        if (sellToken != address(0)) {
            IERC20(sellToken).approve(spender, 0);
        }
    }
}
The executor should already include its liquidation logic, access control, profit checks, and token recovery functions. The example only shows the swap boundary.

Q&A

What should the approval lifecycle be?

For allowance settlement, use scoped approvals. Approve only the amount needed for the input token, execute the swap, then reset the allowance to zero, preferably within the same transaction. This reduces exposure from unused or stale allowances, in addition to the controls Rialto applies on its side.

What should I do if the quote returns issues?

If issues.balance is present, do not execute the swap. If issues.allowance is present for allowance settlement, approve the returned spender before execution.

Safety checks

Before executing a quote, liquidators should still check:
  • expected profit after gas
  • min_buy_amount
  • route freshness
  • slippage tolerance
  • token balances after liquidation
  • allowance reset after execution, for allowance settlement
  • whether the returned transaction still simulates successfully
Quotes depend on live liquidity and may become stale quickly. Request a fresh quote close to execution time.