Skip to main content

When you need an adapter

If your AMM already exposes different function names or argument orders, do not just rename functions and assume it works, because the settle selector is allowlisted onchain and the router patches the input amount at a fixed calldata offset that assumes amountIn is the second argument of swapExactIn. A different layout moves that offset. The clean path is a thin adapter contract that exposes exactly getAmountOut and swapExactIn and forwards to your AMM, roughly 30 lines. If adapters are a dealbreaker across several pairs, talk to Rialto; the selectors and the input-amount offset can be made configurable per pool on Rialto’s side instead.

Adapter skeleton

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

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

contract MyPropPair {
    address public immutable token0;
    address public immutable token1;

    constructor(address _token0, address _token1) {
        token0 = _token0;
        token1 = _token1;
    }

    function getAmountOut(bool zeroForOne, uint256 amountIn)
        external view returns (uint256 amountOut)
    {
        amountOut = _price(zeroForOne, amountIn);
    }

    function swapExactIn(
        bool zeroForOne,
        uint256 amountIn,
        uint256 amountOutMin,
        address to,
        uint256 deadline
    ) external payable returns (uint256 amountOut) {
        if (deadline != 0) require(block.timestamp <= deadline, "expired");
        (address tin, address tout) = zeroForOne ? (token0, token1) : (token1, token0);

        IERC20(tin).transferFrom(msg.sender, address(this), amountIn);
        amountOut = _price(zeroForOne, amountIn);
        require(amountOut >= amountOutMin, "slippage");
        IERC20(tout).transfer(to, amountOut);
    }

    function _price(bool zeroForOne, uint256 amountIn) internal view returns (uint256) {
        // oracle / curve / inventory logic
    }
}