Router

Description:

Decentralized Finance (DeFi) protocol contract providing Mintable, Burnable, Swap, Liquidity, Factory, Oracle functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/Router.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IWETH.sol";
import "./interfaces/IRouter.sol";
import "./interfaces/IFactory.sol";
import "./interfaces/IPair.sol";

/// @title Router is used to swap on Antfarm Protocol without having to own ATF tokens
/// @notice This Version only supports ETH swaps and relies on the ATF/ETH Oracle
contract Router is IRouter {
    address public immutable factory;
    address public immutable protocolToken;
    address public immutable weth;
    address public immutable oraclePair;

    mapping(address => uint256) public userDeposits;
    uint256 public totalDeposits;

    constructor(address _factory, address _weth) {
        factory = _factory;
        protocolToken = IFactory(factory).protocolToken();
        weth = _weth;
        oraclePair = IFactory(factory).getPair(protocolToken, weth, uint16(10));
    }

    modifier ensure(uint256 deadline) {
        if (deadline < block.timestamp) revert Router__Expired();
        _;
    }

    receive() external payable {}

    // Helper function to avoid stack too deep
    function _transferToOracle(uint256 amount, uint256 feeToPay) internal {
        IERC20(weth).transfer(oraclePair, amount);
        IPair(oraclePair).swap(feeToPay, 0, address(this));
    }

    // Helper function to execute swap logic
    function _executeSwapLogic(
        uint256[] memory amounts,
        address pair,
        address _to,
        uint256 _amountIn,
        address _output
    ) internal returns (uint256) {
        (uint256 amount0Out, uint256 amount1Out, uint256 finalFeeToPay) =
            _getFeeToPay(amounts, weth, _output, pair);

        IERC20(weth).transfer(pair, amounts[0]);
        IERC20(protocolToken).transfer(pair, finalFeeToPay);
        IPair(pair).swap(amount0Out, amount1Out, _to);

        _transferToOracle(_amountIn - amounts[0], finalFeeToPay);

        emit SwapExecuted(
            _to, weth, _output, _amountIn, amount0Out + amount1Out
        );

        return amount0Out + amount1Out;
    }

    // INTERNAL WETH SWAP FUNCTIONS
    /// @notice Internal function to swap exact WETH for tokens
    /// @param _amountIn The amount of WETH to swap
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the output tokens
    /// @param _amountOutMin The minimum amount of output tokens to receive
    /// @param _fromUser Whether to transfer WETH from user (true) or use contract's WETH (false)
    /// @return _amountOut The actual amount of output tokens received
    function _swapExactWETHForTokens(
        uint256 _amountIn,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _amountOutMin,
        bool _fromUser
    ) internal returns (uint256 _amountOut) {
        // Transfer WETH from user to this contract (only if _fromUser is true)
        if (_fromUser) {
            IERC20(weth).transferFrom(msg.sender, address(this), _amountIn);
        }

        uint256[] memory amounts = getAmountsOut(_amountIn, weth, _output, _fee);
        address pair = IFactory(factory).getPair(weth, _output, _fee);
        (,, uint256 feeToPay) = _getFeeToPay(amounts, weth, _output, pair);

        // Use 'amounts' to store the required WETH to swap for fee ATF tokens
        amounts = _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));

        uint256 adjustedAmount =
            (_amountIn * _amountIn) / (_amountIn + amounts[0]);
        amounts = getAmountsOut(adjustedAmount, weth, _output, _fee);

        // Checks that the intermediary calculation is already enough
        if (amounts[1] < _amountOutMin) {
            revert Router__InsufficientOutputAmount();
        }

        return _executeSwapLogic(amounts, pair, _to, _amountIn, _output);
    }

    /// @notice Internal function to swap exact tokens for WETH
    /// @param _input The token address to spend
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the WETH
    /// @param _amountIn The amount of input tokens to spend
    /// @param _amountOutMin The minimum amount of WETH to receive
    /// @return _amountOut The actual amount of WETH received
    function _swapExactTokensForWETH(
        address _input,
        uint16 _fee,
        address _to,
        uint256 _amountIn,
        uint256 _amountOutMin
    ) internal returns (uint256 _amountOut) {
        uint256[] memory amounts = getAmountsOut(_amountIn, _input, weth, _fee);
        uint256 standardAmountOut = amounts[1];

        address pair = IFactory(factory).getPair(_input, weth, _fee);

        (uint256 amount0Out, uint256 amount1Out, uint256 feeToPay) =
            _getFeeToPay(amounts, _input, weth, pair);

        if (feeToPay > totalDeposits) {
            revert Router__InsufficientATFBalance();
        }

        amounts = _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));
        if (standardAmountOut - amounts[0] < _amountOutMin) {
            revert Router__InsufficientOutputAmount();
        }

        IERC20(protocolToken).transfer(pair, feeToPay);
        IERC20(_input).transferFrom(msg.sender, pair, _amountIn);

        IPair(pair).swap(amount0Out, amount1Out, _to);

        _amountOut = standardAmountOut - amounts[0];

        _transferToOracle(amounts[0], feeToPay);

        emit SwapExecuted(_to, _input, weth, _amountIn, _amountOut);
    }

    /// @notice Internal function to swap WETH for exact tokens
    /// @param _amountInMax The maximum amount of WETH to spend
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the tokens
    /// @param _amountOut The exact amount of output tokens to receive
    /// @param _fromUser Whether to transfer WETH from user (true) or use contract's WETH (false)
    /// @return _amountIn The actual amount of WETH spent
    function _swapWETHForExactTokens(
        uint256 _amountInMax,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _amountOut,
        bool _fromUser
    ) internal returns (uint256 _amountIn) {
        uint256[] memory amounts =
            _getAmountsIn(_amountOut, weth, _output, _fee);
        address pair = IFactory(factory).getPair(weth, _output, _fee);
        (uint256 amount0Out, uint256 amount1Out, uint256 feeToPay) =
            _getFeeToPay(amounts, weth, _output, pair);

        _amountIn = amounts[0]; // Amount of WETH needed for main swap
        amounts = _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));

        uint256 totalWETHNeeded = _amountIn + amounts[0];
        if (totalWETHNeeded > _amountInMax) {
            revert Router__InsufficientInputAmount();
        }

        // Transfer WETH from user to this contract (only if _fromUser is true)
        if (_fromUser) {
            IERC20(weth).transferFrom(
                msg.sender, address(this), totalWETHNeeded
            );
        }

        IERC20(weth).transfer(pair, _amountIn);
        IERC20(protocolToken).transfer(pair, feeToPay);
        IPair(pair).swap(amount0Out, amount1Out, _to);

        _transferToOracle(amounts[0], feeToPay);

        _amountIn = totalWETHNeeded;

        emit SwapExecuted(_to, weth, _output, _amountIn, _amountOut);
    }

    // MAGIC ROUTER SWAP FUNCTIONS
    /// @inheritdoc IRouter
    function swapExactETHForTokens(
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOutMin
    ) external payable ensure(_deadline) returns (uint256 _amountOut) {
        // Wrap ETH to WETH
        IWETH(weth).deposit{value: msg.value}();

        // Call internal WETH function
        _amountOut = _swapExactWETHForTokens(
            msg.value, _output, _fee, _to, _amountOutMin, false
        );
    }

    /// @inheritdoc IRouter
    function swapExactTokensForETH(
        address _input,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountIn,
        uint256 _amountOutMin
    ) external ensure(_deadline) returns (uint256 _amountOut) {
        // Call internal WETH function with this contract as recipient
        _amountOut = _swapExactTokensForWETH(
            _input, _fee, address(this), _amountIn, _amountOutMin
        );

        // Unwrap WETH to ETH
        IWETH(weth).withdraw(_amountOut);

        // Transfer ETH to recipient
        _safeTransferETH(_to, _amountOut);
    }

    /// @inheritdoc IRouter
    function swapETHForExactTokens(
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOut
    ) external payable ensure(_deadline) returns (uint256 _amountIn) {
        // Wrap all received ETH to WETH
        IWETH(weth).deposit{value: msg.value}();

        // Call internal WETH function
        _amountIn = _swapWETHForExactTokens(
            msg.value, _output, _fee, _to, _amountOut, false
        );

        // Calculate refund amount
        uint256 refund = msg.value - _amountIn;
        if (refund > 0) {
            // Unwrap refunded WETH to ETH
            IWETH(weth).withdraw(refund);
            _safeTransferETH(msg.sender, refund);
        }
    }

    // PUBLIC WETH SWAP FUNCTIONS
    /// @notice Swaps an exact amount of WETH for tokens
    /// @param _amountIn The amount of WETH to swap
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the output tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOutMin The minimum amount of output tokens to receive
    /// @return _amountOut The actual amount of output tokens received
    function swapExactWETHForTokens(
        uint256 _amountIn,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOutMin
    ) external ensure(_deadline) returns (uint256 _amountOut) {
        return _swapExactWETHForTokens(
            _amountIn, _output, _fee, _to, _amountOutMin, true
        );
    }

    /// @notice Swaps an exact amount of tokens for WETH
    /// @param _input The token address to spend
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the WETH
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountIn The amount of input tokens to spend
    /// @param _amountOutMin The minimum amount of WETH to receive
    /// @return _amountOut The actual amount of WETH received
    function swapExactTokensForWETH(
        address _input,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountIn,
        uint256 _amountOutMin
    ) external ensure(_deadline) returns (uint256 _amountOut) {
        uint256 out = _swapExactTokensForWETH(
            _input, _fee, address(this), _amountIn, _amountOutMin
        );
        // router now holds the full WETH, oracle leg already settled inside
        IERC20(weth).transfer(_to, out);
        return out;
    }

    /// @notice Swaps WETH for an exact amount of tokens
    /// @param _amountInMax The maximum amount of WETH to spend
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOut The exact amount of output tokens to receive
    /// @return _amountIn The actual amount of WETH spent
    function swapWETHForExactTokens(
        uint256 _amountInMax,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOut
    ) external ensure(_deadline) returns (uint256 _amountIn) {
        return _swapWETHForExactTokens(
            _amountInMax, _output, _fee, _to, _amountOut, true
        );
    }

    /// @inheritdoc IRouter
    function estimateExactETHForTokens(
        address _output,
        uint16 _fee,
        uint256 _amountIn
    ) external view returns (uint256 estimatedOut) {
        uint256[] memory amounts = getAmountsOut(_amountIn, weth, _output, _fee);
        address pair = IFactory(factory).getPair(weth, _output, _fee);
        (,, uint256 feeToPay) = _getFeeToPay(amounts, weth, _output, pair);

        uint256[] memory feeInAmounts =
            _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));

        feeInAmounts = getAmountsOut(
            (_amountIn * _amountIn) / (_amountIn + feeInAmounts[0]),
            weth,
            _output,
            _fee
        );

        return feeInAmounts[1];
    }

    /// @inheritdoc IRouter
    function estimateExactTokensForETH(
        address _input,
        uint16 _fee,
        uint256 _amountIn
    ) external view returns (uint256 estimatedOut) {
        uint256[] memory amounts = getAmountsOut(_amountIn, _input, weth, _fee);
        uint256 standardAmountOut = amounts[1];

        address pair = IFactory(factory).getPair(_input, weth, _fee);
        (,, uint256 feeToPay) = _getFeeToPay(amounts, _input, weth, pair);

        amounts = _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));

        return standardAmountOut - amounts[0];
    }

    /// @inheritdoc IRouter
    function estimateETHForExactTokens(
        address _output,
        uint16 _fee,
        uint256 _amountOut
    ) external view returns (uint256 estimatedIn) {
        uint256[] memory amounts =
            _getAmountsIn(_amountOut, weth, _output, _fee);

        address pair = IFactory(factory).getPair(weth, _output, _fee);
        (,, uint256 feeToPay) = _getFeeToPay(amounts, weth, _output, pair);

        // Calculate WETH needed to pay for ATF fees
        uint256[] memory feeInAmounts =
            _getAmountsIn(feeToPay, weth, protocolToken, uint16(10));

        // Total ETH needed is the amount for the swap plus the amount needed for fees
        return amounts[0] + feeInAmounts[0];
    }

    /// CLASSIC ROUTER SWAP FUNCTIONS

    /// @notice Swaps an exact amount of input tokens for as many output tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForTokensParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactTokensForTokens(
        swapExactTokensForTokensParams calldata params
    )
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountIn = params.amountIn;
        amounts = getAmountsOut(amountIn, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert Router__InsufficientOutputAmount();
        }
        _safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (_swap(amounts, params.path, params.fees, params.to) > params.maxFee)
        {
            revert Router__InsufficientMaxFee();
        }
    }

    /// @notice Receive an exact amount of output tokens for as few input tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapTokensForExactTokensParams` in calldata
    // @param amountOut The amount of output tokens to receive
    // @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapTokensForExactTokens(
        swapTokensForExactTokensParams calldata params
    )
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountInMax = params.amountInMax;
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > amountInMax) revert Router__ExcessiveInputAmount();
        _safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (_swap(amounts, params.path, params.fees, params.to) > params.maxFee)
        {
            revert Router__InsufficientMaxFee();
        }
    }

    /// @notice Swaps an exact amount of ETH for as many output tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactETHForTokensParams` in calldata
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactETHForTokens(swapExactETHForTokensParams calldata params)
        external
        payable
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[0] != weth) revert Router__InvalidPath();
        amounts = getAmountsOut(msg.value, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert Router__InsufficientOutputAmount();
        }
        IWETH(weth).deposit{value: amounts[0]}();
        assert(
            IWETH(weth).transfer(
                pairFor(params.path[0], params.path[1], params.fees[0]),
                amounts[0]
            )
        );
        if (_swap(amounts, params.path, params.fees, params.to) > params.maxFee)
        {
            revert Router__InsufficientMaxFee();
        }
    }

    /// @notice Receive an exact amount of ETH for as few input tokens as possible
    /// @param params The parameters necessary for the swap, encoded as `swapTokensForExactETHParams` in calldata
    // @param amountOut The amount of ETH to receive
    // @param amountInMax The maximum amount of input tokens that can be required before the transaction reverts
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapTokensForExactETH(swapTokensForExactETHParams calldata params)
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[params.path.length - 1] != weth) {
            revert Router__InvalidPath();
        }
        uint256 amountInMax = params.amountInMax;
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > amountInMax) revert Router__ExcessiveInputAmount();
        _safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, address(this))
                > params.maxFee
        ) {
            revert Router__InsufficientMaxFee();
        }
        IWETH(weth).withdraw(amounts[amounts.length - 1]);
        _safeTransferETH(params.to, amounts[amounts.length - 1]);
    }

    /// @notice Swaps an exact amount of tokens for as much ETH as possible
    /// @param params The parameters necessary for the swap, encoded as `swapExactTokensForETHParams` in calldata
    // @param amountIn The amount of input tokens to send
    // @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapExactTokensForETH(swapExactTokensForETHParams calldata params)
        external
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        uint256 amountIn = params.amountIn;
        if (params.path[params.path.length - 1] != weth) {
            revert Router__InvalidPath();
        }
        amounts = getAmountsOut(amountIn, params.path, params.fees);
        if (amounts[amounts.length - 1] < params.amountOutMin) {
            revert Router__InsufficientOutputAmount();
        }
        _safeTransferFrom(
            params.path[0],
            msg.sender,
            pairFor(params.path[0], params.path[1], params.fees[0]),
            amounts[0]
        );
        if (
            _swap(amounts, params.path, params.fees, address(this))
                > params.maxFee
        ) {
            revert Router__InsufficientMaxFee();
        }
        IWETH(weth).withdraw(amounts[amounts.length - 1]);
        _safeTransferETH(params.to, amounts[amounts.length - 1]);
    }

    /// @notice Receive an exact amount of tokens for as little ETH as possible
    /// @param params The parameters necessary for the swap, encoded as `swapETHForExactTokensParams` in calldata
    // @param amountOut The amount of tokens to receive
    // @param maxFee Maximum fees to be paid
    // @param path An array of token addresses
    // @param fees Associated fee for each two token addresses within the path
    // @param to Recipient of the output tokens
    // @param deadline Unix timestamp after which the transaction will revert
    /// @return amounts The input token amount and all subsequent output token amounts
    function swapETHForExactTokens(swapETHForExactTokensParams calldata params)
        external
        payable
        virtual
        ensure(params.deadline)
        returns (uint256[] memory amounts)
    {
        if (params.path[0] != weth) revert Router__InvalidPath();
        amounts = getAmountsIn(params.amountOut, params.path, params.fees);
        if (amounts[0] > msg.value) revert Router__ExcessiveInputAmount();
        IWETH(weth).deposit{value: amounts[0]}();
        assert(
            IWETH(weth).transfer(
                pairFor(params.path[0], params.path[1], params.fees[0]),
                amounts[0]
            )
        );
        if (_swap(amounts, params.path, params.fees, params.to) > params.maxFee)
        {
            revert Router__InsufficientMaxFee();
        }
        // refund dust ETH if any
        if (msg.value > amounts[0]) {
            _safeTransferETH(msg.sender, msg.value - amounts[0]);
        }
    }

    // fetches and sorts the reserves for a pair
    function getReserves(address tokenA, address tokenB, uint16 fee)
        public
        view
        returns (uint256 reserveA, uint256 reserveB)
    {
        (address token0,) = _sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1,) =
            IPair(pairFor(tokenA, tokenB, fee)).getReserves();
        (reserveA, reserveB) =
            tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    /// @notice Calculates the CREATE2 address for a pair without making any external calls
    /// @param tokenA Token0 from the Pair
    /// @param tokenB Token1 from the Pair
    /// @param fee Associated fee to the Pair
    /// @return pair The CREATE2 address for the desired Pair
    function pairFor(address tokenA, address tokenB, uint16 fee)
        public
        view
        returns (address pair)
    {
        (address token0, address token1) = _sortTokens(tokenA, tokenB);
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(
                                abi.encodePacked(
                                    token0, token1, fee, protocolToken
                                )
                            ),
                            token0 == protocolToken
                                ?
                                hex"e482076c47481b6652287a3b6ef16bc8047ff83dde52d08962662fff8ab4d471" // OraclePair init code hash
                                :
                                hex"d7737950b58d71c23c1376e989549cd028b62f935397f508b68602b01e6a4cdf" // Pair init code hash
                        )
                    )
                )
            )
        );
    }

    // performs chained getAmountOut calculations on any number of pairs
    function getAmountsOut(
        uint256 amountIn,
        address[] memory path,
        uint16[] memory fees
    ) public view returns (uint256[] memory) {
        if (path.length < 2) revert Router__InvalidPath();
        uint256[] memory amounts = new uint256[](path.length);
        amounts[0] = amountIn;
        for (uint256 i; i < path.length - 1; i++) {
            (uint256 reserveIn, uint256 reserveOut) =
                getReserves(path[i], path[i + 1], fees[i]);
            if (path[i] == protocolToken) {
                amounts[i + 1] = getAmountOut(
                    (amounts[i] * 1000) / (1000 + fees[i]),
                    reserveIn,
                    reserveOut
                );
            } else if (path[i + 1] == protocolToken) {
                amounts[i + 1] = (
                    getAmountOut(amounts[i], reserveIn, reserveOut) * 1000
                ) / (1000 + fees[i]);
            } else {
                amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
            }
        }
        return amounts;
    }

    // performs chained getAmountIn calculations on any number of pairs
    function getAmountsIn(
        uint256 amountOut,
        address[] memory path,
        uint16[] memory fees
    ) public view returns (uint256[] memory) {
        if (path.length < 2) revert Router__InvalidPath();
        uint256[] memory amounts = new uint256[](path.length);
        amounts[path.length - 1] = amountOut;
        for (uint256 i = path.length - 1; i > 0; i--) {
            (uint256 reserveIn, uint256 reserveOut) =
                getReserves(path[i - 1], path[i], fees[i - 1]);
            if (path[i - 1] == protocolToken) {
                amounts[i - 1] = (
                    getAmountIn(amounts[i], reserveIn, reserveOut)
                        * (1000 + fees[i - 1])
                ) / 1000;
            } else if (path[i] == protocolToken) {
                amounts[i - 1] = getAmountIn(
                    (amounts[i] * (1000 + fees[i - 1])) / 1000,
                    reserveIn,
                    reserveOut
                );
            } else {
                amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
            }
        }
        return amounts;
    }

    function getAmountsOut(
        uint256 amountIn,
        address tokenIn,
        address tokenOut,
        uint16 fee
    ) internal view returns (uint256[] memory) {
        uint256[] memory amounts = new uint256[](2);
        amounts[0] = amountIn;
        (uint256 reserveIn, uint256 reserveOut) =
            _getReserves(tokenIn, tokenOut, fee);

        if (tokenIn == protocolToken) {
            amounts[1] = _getAmountOut(
                (amountIn * 1000) / (1000 + 10), reserveIn, reserveOut
            );
        } else if (tokenOut == protocolToken) {
            amounts[1] = (_getAmountOut(amountIn, reserveIn, reserveOut) * 1000)
                / (1000 + 10);
        } else {
            amounts[1] = _getAmountOut(amountIn, reserveIn, reserveOut);
        }

        return amounts;
    }

    function _getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256) {
        if (amountIn == 0) revert Router__InsufficientInputAmount();
        if (reserveIn == 0 || reserveOut == 0) {
            revert Router__InsufficientLiquidity();
        }
        uint256 numerator = amountIn * reserveOut;
        uint256 denominator = reserveIn + amountIn;
        return numerator / denominator;
    }

    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256) {
        if (amountIn == 0) revert Router__InsufficientInputAmount();
        if (reserveIn == 0 || reserveOut == 0) {
            revert Router__InsufficientLiquidity();
        }
        uint256 numerator = amountIn * reserveOut;
        uint256 denominator = reserveIn + amountIn;
        return numerator / denominator;
    }

    function _getAmountsIn(
        uint256 amountOut,
        address tokenIn,
        address tokenOut,
        uint16 fee
    ) internal view returns (uint256[] memory) {
        uint256[] memory amounts = new uint256[](2);
        amounts[1] = amountOut;
        (uint256 reserveIn, uint256 reserveOut) =
            _getReserves(tokenIn, tokenOut, fee);
        if (tokenIn == protocolToken) {
            amounts[0] = (
                _getAmountIn(amountOut, reserveIn, reserveOut) * (1000 + 10)
            ) / 1000;
        } else if (tokenOut == protocolToken) {
            amounts[0] = _getAmountIn(
                (amountOut * (1000 + 10)) / 1000, reserveIn, reserveOut
            );
        } else {
            amounts[0] = _getAmountIn(amountOut, reserveIn, reserveOut);
        }
        return amounts;
    }

    function _getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256) {
        if (amountOut == 0) revert Router__InsufficientOutputAmount();
        if (reserveIn == 0 || reserveOut == 0 || amountOut >= reserveOut) {
            revert Router__InsufficientLiquidity();
        }
        uint256 numerator = reserveIn * amountOut;
        uint256 denominator = reserveOut - amountOut;
        return (numerator / denominator) + 1;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut
    ) internal pure returns (uint256) {
        if (amountOut == 0) revert Router__InsufficientOutputAmount();
        if (reserveIn == 0 || reserveOut == 0) {
            revert Router__InsufficientLiquidity();
        }
        uint256 numerator = reserveIn * amountOut;
        uint256 denominator = reserveOut - amountOut;
        return (numerator / denominator) + 1;
    }

    function _getFeeToPay(
        uint256[] memory amounts,
        address tokenIn,
        address tokenOut,
        address pair
    )
        internal
        view
        returns (uint256 amount0Out, uint256 amount1Out, uint256 feeToPay)
    {
        // Original fee calculation for non-ATF pairs
        (address token0,) = _sortTokens(tokenIn, tokenOut);
        (amount0Out, amount1Out) = tokenIn == token0
            ? (uint256(0), amounts[1])
            : (amounts[1], uint256(0));

        uint256 amountIn = amounts[0];

        feeToPay = IPair(pair).getFees(
            amount0Out,
            tokenIn == token0 ? amountIn : uint256(0),
            amount1Out,
            tokenIn == token0 ? uint256(0) : amountIn
        );
    }

    function _getReserves(address tokenA, address tokenB, uint16 fee)
        internal
        view
        returns (uint256 reserveA, uint256 reserveB)
    {
        (address token0,) = _sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1,) =
            IPair(IFactory(factory).getPair(tokenA, tokenB, fee)).getReserves();
        (reserveA, reserveB) =
            tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    function _sortTokens(address tokenA, address tokenB)
        internal
        view
        returns (address token0, address token1)
    {
        if (tokenA == tokenB) revert Router__IdenticalAddresses();
        if (tokenA == protocolToken || tokenB == protocolToken) {
            (token0, token1) = tokenA == protocolToken
                ? (protocolToken, tokenB)
                : (protocolToken, tokenA);
            if (token1 == address(0)) revert Router__AddressZero();
        } else {
            (token0, token1) =
                tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
            if (token0 == address(0)) revert Router__AddressZero();
        }
    }

    function _safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        (bool success, bytes memory data) =
            token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "TransferHelper::transferFrom: transferFrom failed"
        );
    }

    function _safeTransferETH(address to, uint256 value) internal {
        (bool success,) = to.call{value: value}("");
        if (!success) revert Router__ETHTransferFailed();
    }

    function depositATF(uint256 amount) external {
        if (amount == 0) revert Router__ZeroAmount();

        userDeposits[msg.sender] += amount;
        totalDeposits += amount;

        if (
            !IERC20(protocolToken).transferFrom(
                msg.sender, address(this), amount
            )
        ) {
            revert Router__TransferFailed();
        }
    }

    function withdrawATF(uint256 amount) external {
        if (amount == 0) revert Router__ZeroAmount();
        if (amount > userDeposits[msg.sender]) {
            revert Router__InsufficientBalance();
        }

        userDeposits[msg.sender] -= amount;
        totalDeposits -= amount;

        if (!IERC20(protocolToken).transfer(msg.sender, amount)) {
            revert Router__TransferFailed();
        }
    }

    function getDeposit(address user) external view returns (uint256) {
        return userDeposits[user];
    }

    // SWAP
    // requires the initial amount to have already been sent to the first pair
    function _swap(
        uint256[] memory amounts,
        address[] memory path,
        uint16[] memory fees,
        address _to
    ) internal virtual returns (uint256 totalFee) {
        for (uint256 i; i < path.length - 1; i++) {
            (address input, address output) = (path[i], path[i + 1]);
            uint16 fee = fees[i];
            IPair pair = IPair(pairFor(input, output, fee));

            (address token0,) = _sortTokens(input, output);
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amounts[i + 1])
                : (amounts[i + 1], uint256(0));

            {
                uint256 amountIn = amounts[i];

                if (input == protocolToken) {
                    totalFee = totalFee + ((amountIn * fee) / (1000 + fee));
                } else if (output == protocolToken) {
                    totalFee = totalFee + ((amounts[i + 1] * fee) / 1000);
                } else {
                    uint256 feeToPay = pair.getFees(
                        amount0Out,
                        input == token0 ? amountIn : uint256(0),
                        amount1Out,
                        input == token0 ? uint256(0) : amountIn
                    );

                    _safeTransferFrom(
                        protocolToken, msg.sender, address(pair), feeToPay
                    );

                    totalFee = totalFee + feeToPay;
                }
            }

            address to = i < path.length - 2
                ? pairFor(output, path[i + 2], fees[i + 1])
                : _to;
            pair.swap(amount0Out, amount1Out, to);
        }
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
    },
    "src/interfaces/IWETH.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IWETH {
    // ERC20-like functions
    function deposit() external payable;
    function withdraw(uint256) external;

    // Standard ERC20 functions
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);
    function allowance(address owner, address spender)
        external
        view
        returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount)
        external
        returns (bool);

    // Events
    event Deposit(address indexed dst, uint256 wad);
    event Withdrawal(address indexed src, uint256 wad);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner, address indexed spender, uint256 value
    );
}
"
    },
    "src/interfaces/IRouter.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/// @title Router Interface for Antfarm Protocol
/// @notice Interface for handling token swaps with ETH on Antfarm Protocol
/// @dev Implements core swap functionality and estimation methods
interface IRouter {
    error Router__Expired();
    error Router__IdenticalAddresses();
    error Router__AddressZero();
    error Router__ZeroAmount();
    error Router__InsufficientLiquidity();
    error Router__InsufficientInputAmount();
    error Router__InsufficientOutputAmount();
    error Router__ETHTransferFailed();
    error Router__InsufficientBalance();
    error Router__InsufficientATFBalance();
    error Router__TransferFailed();
    error Router__InsufficientMaxFee();
    error Router__ExcessiveInputAmount();
    error Router__InvalidPath();

    event SwapExecuted(
        address indexed sender,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256 amountIn,
        uint256 amountOut
    );

    /// @notice Returns the factory contract address
    /// @return Address of the factory contract
    function factory() external view returns (address);

    /// @notice Returns the Antfarm token address
    /// @return Address of the Antfarm token
    function protocolToken() external view returns (address);

    /// @notice Returns the WETH token address
    /// @return Address of the WETH token
    function weth() external view returns (address);

    /// @notice Returns the oracle pair address
    /// @return Address of the oracle pair
    function oraclePair() external view returns (address);

    /// @notice Allows the contract to receive ETH
    receive() external payable;

    /// @notice Swaps an exact amount of ETH for tokens
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the output tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOutMin The minimum amount of output tokens to receive
    /// @return _amountOut The actual amount of output tokens received
    function swapExactETHForTokens(
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOutMin
    ) external payable returns (uint256 _amountOut);

    /// @notice Swaps an exact amount of tokens for ETH
    /// @param _input The token address to spend
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the ETH
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountIn The amount of input tokens to spend
    /// @param _amountOutMin The minimum amount of ETH to receive
    /// @return _amountOut The actual amount of ETH received
    function swapExactTokensForETH(
        address _input,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountIn,
        uint256 _amountOutMin
    ) external returns (uint256 _amountOut);

    /// @notice Swaps ETH for an exact amount of tokens
    /// @dev Refunds excess ETH if too much is sent
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOut The exact amount of output tokens to receive
    /// @return _amountIn The amount of ETH spent
    function swapETHForExactTokens(
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOut
    ) external payable returns (uint256 _amountIn);

    /// @notice Estimates the output amount of tokens for an exact ETH input
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _amountIn The amount of ETH to swap
    /// @return estimatedOut The estimated amount of output tokens
    function estimateExactETHForTokens(
        address _output,
        uint16 _fee,
        uint256 _amountIn
    ) external view returns (uint256 estimatedOut);

    /// @notice Estimates the output amount of ETH for an exact token input
    /// @param _input The token address to spend
    /// @param _fee The fee tier of the pool
    /// @param _amountIn The amount of input tokens
    /// @return estimatedOut The estimated amount of ETH
    function estimateExactTokensForETH(
        address _input,
        uint16 _fee,
        uint256 _amountIn
    ) external view returns (uint256 estimatedOut);

    /// @notice Estimates the input amount of ETH needed for an exact token output
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _amountOut The exact amount of output tokens desired
    /// @return estimatedIn The estimated amount of ETH needed
    function estimateETHForExactTokens(
        address _output,
        uint16 _fee,
        uint256 _amountOut
    ) external view returns (uint256 estimatedIn);

    /// @notice Swaps an exact amount of WETH for tokens
    /// @param _amountIn The amount of WETH to swap
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the output tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOutMin The minimum amount of output tokens to receive
    /// @return _amountOut The actual amount of output tokens received
    function swapExactWETHForTokens(
        uint256 _amountIn,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOutMin
    ) external returns (uint256 _amountOut);

    /// @notice Swaps an exact amount of tokens for WETH
    /// @param _input The token address to spend
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the WETH
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountIn The amount of input tokens to spend
    /// @param _amountOutMin The minimum amount of WETH to receive
    /// @return _amountOut The actual amount of WETH received
    function swapExactTokensForWETH(
        address _input,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountIn,
        uint256 _amountOutMin
    ) external returns (uint256 _amountOut);

    /// @notice Swaps WETH for an exact amount of tokens
    /// @param _amountInMax The maximum amount of WETH to spend
    /// @param _output The token address to receive
    /// @param _fee The fee tier of the pool
    /// @param _to The recipient address for the tokens
    /// @param _deadline The timestamp by which the transaction must be executed
    /// @param _amountOut The exact amount of output tokens to receive
    /// @return _amountIn The actual amount of WETH spent
    function swapWETHForExactTokens(
        uint256 _amountInMax,
        address _output,
        uint16 _fee,
        address _to,
        uint256 _deadline,
        uint256 _amountOut
    ) external returns (uint256 _amountIn);

    struct swapParams {
        address[] path;
        uint16[] fees;
        address to;
    }

    struct swapExactTokensForTokensParams {
        uint256 amountIn;
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactTokensForTokens(
        swapExactTokensForTokensParams calldata params
    ) external returns (uint256[] memory amounts);

    struct swapTokensForExactTokensParams {
        uint256 amountOut;
        uint256 amountInMax;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapTokensForExactTokens(
        swapTokensForExactTokensParams calldata params
    ) external returns (uint256[] memory amounts);

    struct swapExactETHForTokensParams {
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactETHForTokens(swapExactETHForTokensParams calldata params)
        external
        payable
        returns (uint256[] memory amounts);

    struct swapTokensForExactETHParams {
        uint256 amountOut;
        uint256 amountInMax;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapTokensForExactETH(swapTokensForExactETHParams calldata params)
        external
        returns (uint256[] memory amounts);

    struct swapExactTokensForETHParams {
        uint256 amountIn;
        uint256 amountOutMin;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapExactTokensForETH(swapExactTokensForETHParams calldata params)
        external
        returns (uint256[] memory amounts);

    struct swapETHForExactTokensParams {
        uint256 amountOut;
        uint256 maxFee;
        address[] path;
        uint16[] fees;
        address to;
        uint256 deadline;
    }

    function swapETHForExactTokens(swapETHForExactTokensParams calldata params)
        external
        payable
        returns (uint256[] memory amounts);

    /// @notice Deposits ATF tokens
    /// @param amount The amount of ATF tokens to deposit
    function depositATF(uint256 amount) external;

    /// @notice Withdraws ATF tokens
    /// @param amount The amount of ATF tokens to withdraw
    function withdrawATF(uint256 amount) external;

    /// @notice Gets the deposit amount for a user
    /// @param user The address of the user
    /// @return The deposit amount for the user
    function getDeposit(address user) external view returns (uint256);

    /// @notice Returns the deposit amount for a user
    /// @param user The address of the user
    /// @return The deposit amount for the user
    function userDeposits(address user) external view returns (uint256);

    // fetches and sorts the reserves for a pair
    function getReserves(address tokenA, address tokenB, uint16 fee)
        external
        view
        returns (uint256 reserveA, uint256 reserveB);
}
"
    },
    "src/interfaces/IFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IFactory {
    event PairCreated(
        address indexed token0,
        address indexed token1,
        address pair,
        uint16 fee,
        uint256 allPairsLength
    );

    function possibleFees(uint256) external view returns (uint16);

    function allPairs(uint256) external view returns (address);

    function protocolToken() external view returns (address);

    function getPairs(uint256 startIndex, uint256 numOfPairs)
        external
        view
        returns (address[] memory, uint256);

    function getPair(address tokenA, address tokenB, uint16 fee)
        external
        view
        returns (address pair);

    function feesForPair(address tokenA, address tokenB, uint256)
        external
        view
        returns (uint16);

    function getFeesForPair(address tokenA, address tokenB)
        external
        view
        returns (uint16[8] memory fees);

    function allPairsLength() external view returns (uint256);

    function createPair(address tokenA, address tokenB, uint16 fee)
        external
        returns (address pair);
}
"
    },
    "src/interfaces/IPair.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IPair {
    error BalanceOverflow();
    error InsufficientFee();
    error InsufficientInputAmount();
    error InsufficientLiquidity();
    error InsufficientLiquidityBurned();
    error InsufficientLiquidityMinted();
    error InsufficientOutputAmount();
    error InvalidReceiver();
    error K();
    error NoBetterOracle();
    error NoOracleFound();
    error SenderNotFactory();
    error SwapAmountTooLow();

    event Burn(
        address indexed sender,
        uint256 amount0,
        uint256 amount1,
        address indexed to
    );
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Swap(
        address indexed sender,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amount0Out,
        uint256 amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function antfarmOracle() external view returns (address);
    function antfarmToken() external view returns (address);
    function antfarmTokenReserve() external view returns (uint256);
    function burn(address to, uint256 positionId, uint256 liquidity)
        external
        returns (uint256, uint256);
    function claimDividend(address to, uint256 positionId)
        external
        returns (uint256 claimAmount);
    function claimableDividends(address operator, uint256 positionId)
        external
        view
        returns (uint256 amount);
    function factory() external view returns (address);
    function fee() external view returns (uint16);
    function getFees(
        uint256 amount0Out,
        uint256 amount0In,
        uint256 amount1Out,
        uint256 amount1In
    ) external view returns (uint256 feeToPay);
    function getPositionLP(address operator, uint256 positionId)
        external
        view
        returns (uint128);
    function getReserves()
        external
        view
        returns (
            uint112 _reserve0,
            uint112 _reserve1,
            uint32 _blockTimestampLast
        );
    function initialize(
        address _token0,
        address _token1,
        uint16 _fee,
        address _antfarmToken
    ) external;
    function mint(address to, uint256 positionId) external returns (uint256);
    function positions(address, uint256)
        external
        view
        returns (uint128 lp, uint256 dividend, uint256 lastDividendPoints);
    function scanOracles(uint112 maxReserve)
        external
        view
        returns (address bestOracle);
    function skim(address to) external;
    function swap(uint256 amount0Out, uint256 amount1Out, address to)
        external;
    function sync() external;
    function token0() external view returns (address);
    function token1() external view returns (address);
    function totalSupply() external view returns (uint256);
    function updateOracle() external;
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
      "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 1000
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "shanghai",
    "viaIR": false
  }
}}

Tags:
ERC20, DeFi, Mintable, Burnable, Swap, Liquidity, Factory, Oracle|addr:0x6b8cd00eeff2e8d9f563869b068d9c64ef1dd791|verified:true|block:23619318|tx:0xadb28862526ea0c344dcdce148daa0c9f534486bca026a9b9d20b2ed84b9e26a|first_check:1760969834

Submitted on: 2025-10-20 16:17:14

Comments

Log in to comment.

No comments yet.