AVAX Price: $25.28 (-3.90%)
Gas: 1.9 nAVAX
 

Overview

AVAX Balance

Avalanche C-Chain LogoAvalanche C-Chain LogoAvalanche C-Chain Logo0 AVAX

AVAX Value

$0.00

Multichain Info

1 address found via
Transaction Hash
Method
Block
From
To
Swap Exact In571912172025-02-12 3:37:4215 secs ago1739331462IN
0x45A62B09...863E2c86b
0 AVAX0.001367052.5
Swap Exact In571912082025-02-12 3:37:2829 secs ago1739331448IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571911442025-02-12 3:35:222 mins ago1739331322IN
0x45A62B09...863E2c86b
0 AVAX0.000516232.5
Swap Exact In571911422025-02-12 3:35:192 mins ago1739331319IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571910862025-02-12 3:33:274 mins ago1739331207IN
0x45A62B09...863E2c86b
0 AVAX0.000451562.5
Swap Exact In571910752025-02-12 3:33:114 mins ago1739331191IN
0x45A62B09...863E2c86b
1 AVAX0.000450272.5
Swap Exact In571910382025-02-12 3:32:055 mins ago1739331125IN
0x45A62B09...863E2c86b
0 AVAX0.000142571
Swap Exact In571910342025-02-12 3:31:546 mins ago1739331114IN
0x45A62B09...863E2c86b
0 AVAX0.001459972.5
Swap Exact In571910082025-02-12 3:31:046 mins ago1739331064IN
0x45A62B09...863E2c86b
0 AVAX0.000142571
Swap Exact In571909742025-02-12 3:30:067 mins ago1739331006IN
0x45A62B09...863E2c86b
0 AVAX0.000629551
Swap Exact In571908152025-02-12 3:25:1212 mins ago1739330712IN
0x45A62B09...863E2c86b
0 AVAX0.000143531.00957258
Swap Exact In571907842025-02-12 3:24:1813 mins ago1739330658IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571907542025-02-12 3:23:1814 mins ago1739330598IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571907332025-02-12 3:22:3715 mins ago1739330557IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571907202025-02-12 3:22:1815 mins ago1739330538IN
0x45A62B09...863E2c86b
0 AVAX0.001600562.5
Swap Exact In571907192025-02-12 3:22:1715 mins ago1739330537IN
0x45A62B09...863E2c86b
0 AVAX0.000250031
Swap Exact In571907022025-02-12 3:21:5316 mins ago1739330513IN
0x45A62B09...863E2c86b
0 AVAX0.000766321
Swap Exact In571905922025-02-12 3:18:4319 mins ago1739330323IN
0x45A62B09...863E2c86b
0 AVAX0.000429052.5
Swap Exact In571905262025-02-12 3:16:3421 mins ago1739330194IN
0x45A62B09...863E2c86b
0.0001044 AVAX0.000865242.5
Swap Exact In571905212025-02-12 3:16:2621 mins ago1739330186IN
0x45A62B09...863E2c86b
0 AVAX0.000142171
Swap Exact In571905112025-02-12 3:16:0521 mins ago1739330165IN
0x45A62B09...863E2c86b
0 AVAX0.000445432.5
Swap Exact In571904742025-02-12 3:14:5423 mins ago1739330094IN
0x45A62B09...863E2c86b
0 AVAX0.000142571
Swap Exact In571904552025-02-12 3:14:1423 mins ago1739330054IN
0x45A62B09...863E2c86b
0 AVAX0.000583011.25
Swap Exact In571904372025-02-12 3:13:4124 mins ago1739330021IN
0x45A62B09...863E2c86b
0 AVAX0.000414462.5
Swap Exact In571904222025-02-12 3:13:1024 mins ago1739329990IN
0x45A62B09...863E2c86b
0 AVAX0.000431422.60228771
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
571911442025-02-12 3:35:222 mins ago1739331322
0x45A62B09...863E2c86b
0.22412329 AVAX
571911442025-02-12 3:35:222 mins ago1739331322
0x45A62B09...863E2c86b
0.22412329 AVAX
571910862025-02-12 3:33:274 mins ago1739331207
0x45A62B09...863E2c86b
2.87122111 AVAX
571910862025-02-12 3:33:274 mins ago1739331207
0x45A62B09...863E2c86b
2.87122111 AVAX
571910752025-02-12 3:33:114 mins ago1739331191
0x45A62B09...863E2c86b
1 AVAX
571910342025-02-12 3:31:546 mins ago1739331114
0x45A62B09...863E2c86b
0.91479321 AVAX
571910342025-02-12 3:31:546 mins ago1739331114
0x45A62B09...863E2c86b
0.91479321 AVAX
571909742025-02-12 3:30:067 mins ago1739331006
0x45A62B09...863E2c86b
157.85524039 AVAX
571909742025-02-12 3:30:067 mins ago1739331006
0x45A62B09...863E2c86b
157.85524039 AVAX
571907202025-02-12 3:22:1815 mins ago1739330538
0x45A62B09...863E2c86b
39.57654921 AVAX
571907202025-02-12 3:22:1815 mins ago1739330538
0x45A62B09...863E2c86b
39.57654921 AVAX
571907022025-02-12 3:21:5316 mins ago1739330513
0x45A62B09...863E2c86b
118.86942077 AVAX
571907022025-02-12 3:21:5316 mins ago1739330513
0x45A62B09...863E2c86b
118.86942077 AVAX
571905262025-02-12 3:16:3421 mins ago1739330194
0x45A62B09...863E2c86b
0.0001044 AVAX
571905112025-02-12 3:16:0521 mins ago1739330165
0x45A62B09...863E2c86b
0.53537004 AVAX
571905112025-02-12 3:16:0521 mins ago1739330165
0x45A62B09...863E2c86b
0.53537004 AVAX
571903352025-02-12 3:10:2727 mins ago1739329827
0x45A62B09...863E2c86b
0.00013648 AVAX
571902762025-02-12 3:08:4429 mins ago1739329724
0x45A62B09...863E2c86b
0.01683195 AVAX
571902762025-02-12 3:08:4429 mins ago1739329724
0x45A62B09...863E2c86b
0.01683195 AVAX
571901882025-02-12 3:06:5930 mins ago1739329619
0x45A62B09...863E2c86b
0.1 AVAX
571899232025-02-12 2:58:3539 mins ago1739329115
0x45A62B09...863E2c86b
1.5 AVAX
571897022025-02-12 2:52:2445 mins ago1739328744
0x45A62B09...863E2c86b
0.08954002 AVAX
571897022025-02-12 2:52:2445 mins ago1739328744
0x45A62B09...863E2c86b
0.08954002 AVAX
571896932025-02-12 2:52:0845 mins ago1739328728
0x45A62B09...863E2c86b
1.02885736 AVAX
571896932025-02-12 2:52:0845 mins ago1739328728
0x45A62B09...863E2c86b
1.02885736 AVAX
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Router

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 9 : Router.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {TokenLib} from "./libraries/TokenLib.sol";
import {RouterLib} from "./libraries/RouterLib.sol";
import {IRouter} from "./interfaces/IRouter.sol";

/**
 * @title Router
 * @dev Router contract for swapping tokens using a predefined route.
 * The route must follow the PackedRoute format.
 */
contract Router is Ownable2Step, ReentrancyGuard, IRouter {
    using EnumerableSet for EnumerableSet.AddressSet;

    address public immutable WNATIVE;

    EnumerableSet.AddressSet private _trustedLogics;

    /**
     * @dev The allowances represent the maximum amount of tokens that the logic contract can spend on behalf of the sender.
     * It is always reseted at the end of the swap.
     * The key is calculated as keccak256(abi.encodePacked(token, sender, user)).
     */
    mapping(bytes32 key => uint256 allowance) private _allowances;

    /**
     * @dev Constructor for the Router contract.
     *
     * Requirements:
     * - The wnative address must be a contract with code.
     */
    constructor(address wnative, address initialOwner) Ownable(initialOwner) {
        if (address(wnative).code.length == 0) revert Router__InvalidWnative();

        WNATIVE = wnative;
    }

    /**
     * @dev Only allows native token to be received from unwrapping wnative.
     */
    receive() external payable {
        if (msg.sender != WNATIVE) revert Router__OnlyWnative();
    }

    /**
     * @dev Fallback function to validate and transfer tokens.
     */
    fallback() external {
        RouterLib.validateAndTransfer(_allowances);
    }

    /**
     * @dev Returns the logic contract address at the specified index.
     */
    function getTrustedLogicAt(
        uint256 index
    ) external view override returns (address) {
        return _trustedLogics.at(index);
    }

    /**
     * @dev Returns the number of trusted logic contracts.
     */
    function getTrustedLogicLength() external view override returns (uint256) {
        return _trustedLogics.length();
    }

    /**
     * @dev Swaps tokens from the sender to the recipient using the exact input amount. It will use the specified logic contract.
     *
     * Emits a {SwapExactIn} event.
     *
     * Requirements:
     * - The logic contract must be a trusted logic contract.
     * - The recipient address must not be zero or the router address.
     * - The deadline must not have passed.
     * - The input token and output token must not be the same.
     * - If the amountIn is zero, the entire balance of the input token will be used and it must not be zero.
     * - The entire amountIn of the input token must be spent.
     * - The actual amount of tokenOut received must be greater than or equal to the amountOutMin.
     */
    function swapExactIn(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOutMin,
        address to,
        uint256 deadline,
        bytes calldata route
    )
        external
        payable
        override
        nonReentrant
        returns (uint256 totalIn, uint256 totalOut)
    {
        if (amountIn == 0)
            amountIn = tokenIn == address(0)
                ? msg.value
                : TokenLib.balanceOf(tokenIn, msg.sender);

        _verifyParameters(amountIn, amountOutMin, to, deadline);

        (totalIn, totalOut) = _swap(
            logic,
            tokenIn,
            tokenOut,
            amountIn,
            amountOutMin,
            msg.sender,
            to,
            route,
            true
        );

        emit SwapExactIn(msg.sender, to, tokenIn, tokenOut, totalIn, totalOut);
    }

    /**
     * @dev Swaps tokens from the sender to the recipient using the exact output amount. It will use the specified logic contract.
     *
     * Emits a {SwapExactOut} event.
     *
     * Requirements:
     * - The logic contract must be a trusted logic contract.
     * - The recipient address must not be zero or the router address.
     * - The deadline must not have passed.
     * - The input token and output token must not be the same.
     * - If the amountInMax is zero, the entire balance of the input token will be used and it must not be zero.
     * - The actual amount of tokenIn spent must be less than or equal to the amountInMax.
     * - The actual amount of tokenOut received must be greater than or equal to the amountOut.
     */
    function swapExactOut(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountOut,
        uint256 amountInMax,
        address to,
        uint256 deadline,
        bytes calldata route
    )
        external
        payable
        override
        nonReentrant
        returns (uint256 totalIn, uint256 totalOut)
    {
        _verifyParameters(amountInMax, amountOut, to, deadline);

        (totalIn, totalOut) = _swap(
            logic,
            tokenIn,
            tokenOut,
            amountInMax,
            amountOut,
            msg.sender,
            to,
            route,
            false
        );

        emit SwapExactOut(msg.sender, to, tokenIn, tokenOut, totalIn, totalOut);
    }

    /**
     * @dev Simulates the swap of tokens using multiple routes and the specified logic contract.
     * The simulation will revert with an array of amounts if the swap is valid.
     */
    function simulate(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address to,
        bool exactIn,
        bytes[] calldata multiRoutes
    ) external payable override {
        uint256 length = multiRoutes.length;

        uint256[] memory amounts = new uint256[](length);
        for (uint256 i; i < length; ) {
            (, bytes memory data) = address(this).delegatecall(
                abi.encodeWithSelector(
                    IRouter.simulateSingle.selector,
                    logic,
                    tokenIn,
                    tokenOut,
                    amountIn,
                    amountOut,
                    to,
                    exactIn,
                    multiRoutes[i++]
                )
            );

            if (bytes4(data) == IRouter.Router__SimulateSingle.selector) {
                assembly ("memory-safe") {
                    mstore(add(amounts, mul(i, 32)), mload(add(data, 36)))
                }
            } else {
                amounts[i - 1] = exactIn ? 0 : type(uint256).max;
            }
        }

        revert Router__Simulations(amounts);
    }

    /**
     * @dev Simulates the swap of tokens using a single route and the specified logic contract.
     * The simulation will revert with the total amount of tokenIn or tokenOut if the swap is valid.
     */
    function simulateSingle(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address to,
        bool exactIn,
        bytes calldata route
    ) external payable override {
        _verifyParameters(amountIn, amountOut, to, block.timestamp);

        (uint256 totalIn, uint256 totalOut) = _swap(
            logic,
            tokenIn,
            tokenOut,
            amountIn,
            amountOut,
            msg.sender,
            to,
            route,
            exactIn
        );

        revert Router__SimulateSingle(exactIn ? totalOut : totalIn);
    }

    /**
     * @dev Updates the logic contract address.
     *
     * Emits a {RouterLogicUpdated} event.
     *
     * Requirements:
     * - The caller must be the owner.
     */
    function updateRouterLogic(
        address logic,
        bool add
    ) external override onlyOwner {
        if (add) {
            if (!_trustedLogics.add(logic))
                revert Router__LogicAlreadyAdded(logic);
        } else {
            if (!_trustedLogics.remove(logic))
                revert Router__LogicNotFound(logic);
        }

        emit RouterLogicUpdated(logic, add);
    }

    /**
     * @dev Helper function to verify the input parameters of a swap.
     *
     * Requirements:
     * - The recipient address must not be zero or the router address.
     * - The deadline must not have passed.
     * - The amounts must not be zero.
     */
    function _verifyParameters(
        uint256 amountIn,
        uint256 amountOut,
        address to,
        uint256 deadline
    ) internal view {
        if (to == address(0) || to == address(this)) revert Router__InvalidTo();
        if (block.timestamp > deadline) revert Router__DeadlineExceeded();
        if (amountIn == 0 || amountOut == 0) revert Router__ZeroAmount();
    }

    /**
     * @dev Helper function to verify the output of a swap.
     *
     * Requirements:
     * - The actual amount of tokenOut returned by the logic contract must be greater than the amountOutMin.
     * - The actual balance increase of the recipient must be greater than the amountOutMin.
     */
    function _verifySwap(
        address tokenOut,
        address to,
        uint256 balance,
        uint256 amountOutMin,
        uint256 amountOut
    ) internal view returns (uint256) {
        if (amountOut < amountOutMin)
            revert Router__InsufficientOutputAmount(amountOut, amountOutMin);

        uint256 balanceAfter = TokenLib.universalBalanceOf(tokenOut, to);

        if (balanceAfter < balance + amountOutMin) {
            revert Router__InsufficientAmountReceived(
                balance,
                balanceAfter,
                amountOutMin
            );
        }

        unchecked {
            return balanceAfter - balance;
        }
    }

    /**
     * @dev Helper function to call the logic contract to swap tokens.
     * It will use the specified logic contract to swap the input token to the output token.
     * This function will wrap the input token if it is native and unwrap the output token if it is native.
     * It will also refund the sender if there is any excess amount of native token.
     * It will allow the logic contract to spend at most amountIn of the input token from the sender, and reset
     * the allowance after the swap, see {RouterLib.swap}.
     *
     * Requirements:
     * - The logic contract must be a trusted logic contract.
     * - If the swap is exactIn, the totalIn must be equal to the amountIn.
     * - If the swap is exactOut, the totalIn must be less than or equal to the amountIn.
     */
    function _swap(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address from,
        address to,
        bytes calldata route,
        bool exactIn
    ) internal returns (uint256 totalIn, uint256 totalOut) {
        if (!_trustedLogics.contains(logic))
            revert Router__UntrustedLogic(logic);

        address recipient;
        (recipient, tokenOut) = tokenOut == address(0)
            ? (address(this), WNATIVE)
            : (to, tokenOut);

        if (tokenIn == address(0)) {
            tokenIn = WNATIVE;
            from = address(this);
            TokenLib.wrap(WNATIVE, amountIn);
        }

        if (tokenIn == tokenOut) revert Router__IdenticalTokens();

        uint256 balance = TokenLib.universalBalanceOf(tokenOut, recipient);

        address logic_ = logic; // avoid stack too deep error

        (totalIn, totalOut) = RouterLib.swap(
            _allowances,
            tokenIn,
            tokenOut,
            amountIn,
            amountOut,
            from,
            recipient,
            route,
            exactIn,
            logic_
        );

        if (recipient == address(this)) {
            totalOut = _verifySwap(
                tokenOut,
                recipient,
                balance,
                amountOut,
                totalOut
            );

            TokenLib.unwrap(WNATIVE, totalOut);
            TokenLib.transferNative(to, totalOut);
        } else {
            totalOut = _verifySwap(tokenOut, to, balance, amountOut, totalOut);
        }

        unchecked {
            uint256 refund;
            if (from == address(this)) {
                uint256 unwrap = amountIn - totalIn;
                if (unwrap > 0) TokenLib.unwrap(WNATIVE, unwrap);

                refund = msg.value + unwrap - amountIn;
            } else {
                refund = msg.value;
            }

            if (refund > 0) TokenLib.transferNative(msg.sender, refund);
        }
    }
}

File 2 of 9 : Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {Ownable} from "./Ownable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

File 3 of 9 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 4 of 9 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 5 of 9 : TokenLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title TokenLib
 * @dev Helper library for token operations, such as balanceOf, transfer, transferFrom, wrap, and unwrap.
 */
library TokenLib {
    error TokenLib__BalanceOfFailed();
    error TokenLib__WrapFailed();
    error TokenLib__UnwrapFailed();
    error TokenLib__NativeTransferFailed();
    error TokenLib__TransferFromFailed();
    error TokenLib__TransferFailed();

    /**
     * @dev Returns the balance of a token for an account.
     *
     * Requirements:
     * - The call must succeed.
     * - The target contract must return at least 32 bytes.
     */
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        uint256 success;
        uint256 returnDataSize;

        assembly ("memory-safe") {
            mstore(0, 0x70a08231) // balanceOf(address)
            mstore(32, account)

            success := staticcall(gas(), token, 28, 36, 0, 32)

            returnDataSize := returndatasize()

            amount := mload(0)
        }

        if (success == 0) _tryRevertWithReason();

        // If call failed, and it didn't already bubble up the revert reason, then the return data size must be 0,
        // which will revert here with a generic error message
        if (returnDataSize < 32) revert TokenLib__BalanceOfFailed();
    }

    /**
     * @dev Returns the balance of a token for an account, or the native balance of the account if the token is the native token.
     *
     * Requirements:
     * - The call must succeed (if the token is not the native token).
     * - The target contract must return at least 32 bytes (if the token is not the native token).
     */
    function universalBalanceOf(address token, address account) internal view returns (uint256 amount) {
        return token == address(0) ? account.balance : balanceOf(token, account);
    }

    /**
     * @dev Transfers native tokens to an account.
     *
     * Requirements:
     * - The call must succeed.
     */
    function transferNative(address to, uint256 amount) internal {
        uint256 success;

        assembly ("memory-safe") {
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        if (success == 0) {
            _tryRevertWithReason();
            revert TokenLib__NativeTransferFailed();
        }
    }

    /**
     * @dev Transfers tokens from an account to another account.
     * This function does not check if the target contract has code, this should be done before calling this function
     *
     * Requirements:
     * - The call must succeed.
     */
    function wrap(address wnative, uint256 amount) internal {
        uint256 success;

        assembly ("memory-safe") {
            mstore(0, 0xd0e30db0) // deposit()

            success := call(gas(), wnative, amount, 28, 4, 0, 0)
        }

        if (success == 0) {
            _tryRevertWithReason();
            revert TokenLib__WrapFailed();
        }
    }

    /**
     * @dev Transfers tokens from an account to another account.
     * This function does not check if the target contract has code, this should be done before calling this function
     *
     * Requirements:
     * - The call must succeed.
     */
    function unwrap(address wnative, uint256 amount) internal {
        uint256 success;

        assembly ("memory-safe") {
            mstore(0, 0x2e1a7d4d) // withdraw(uint256)
            mstore(32, amount)

            success := call(gas(), wnative, 0, 28, 36, 0, 0)
        }

        if (success == 0) {
            _tryRevertWithReason();
            revert TokenLib__UnwrapFailed();
        }
    }

    /**
     * @dev Transfers tokens from an account to another account.
     *
     * Requirements:
     * - The call must succeed
     * - The target contract must either return true or no value.
     * - The target contract must have code.
     */
    function transfer(address token, address to, uint256 amount) internal {
        uint256 success;
        uint256 returnSize;
        uint256 returnValue;

        assembly ("memory-safe") {
            let m0x40 := mload(0x40)

            mstore(0, 0xa9059cbb) // transfer(address,uint256)
            mstore(32, to)
            mstore(64, amount)

            success := call(gas(), token, 0, 28, 68, 0, 32)

            returnSize := returndatasize()
            returnValue := mload(0)

            mstore(0x40, m0x40)
        }

        if (success == 0) {
            _tryRevertWithReason();
            revert TokenLib__TransferFailed();
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) revert TokenLib__TransferFailed();
    }

    /**
     * @dev Transfers tokens from an account to another account.
     *
     * Requirements:
     * - The call must succeed.
     * - The target contract must either return true or no value.
     * - The target contract must have code.
     */
    function transferFrom(address token, address from, address to, uint256 amount) internal {
        uint256 success;
        uint256 returnSize;
        uint256 returnValue;

        assembly ("memory-safe") {
            let m0x40 := mload(0x40)
            let m0x60 := mload(0x60)

            mstore(0, 0x23b872dd) // transferFrom(address,address,uint256)
            mstore(32, from)
            mstore(64, to)
            mstore(96, amount)

            success := call(gas(), token, 0, 28, 100, 0, 32)

            returnSize := returndatasize()
            returnValue := mload(0)

            mstore(0x40, m0x40)
            mstore(0x60, m0x60)
        }

        if (success == 0) {
            _tryRevertWithReason();
            revert TokenLib__TransferFromFailed();
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) revert TokenLib__TransferFromFailed();
    }

    /**
     * @dev Tries to bubble up the revert reason.
     * This function needs to be called only if the call has failed, and will revert if there is a revert reason.
     * This function might no revert if there is no revert reason, always use it in conjunction with a revert.
     */
    function _tryRevertWithReason() private pure {
        assembly ("memory-safe") {
            if returndatasize() {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }
}

File 6 of 9 : RouterLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./TokenLib.sol";

/**
 * @title RouterLib
 * @dev Helper library for router operations, such as validateAndTransfer, transfer, and swap.
 * The router must implement a fallback function that uses `validateAndTransfer` to validate the allowance
 * and transfer the tokens and functions that uses `swap` to call the router logic to swap tokens.
 * The router logic must implement the `swapExactIn` and `swapExactOut` functions to swap tokens and
 * use the `transfer` function to transfer tokens from the router according to the route selected.
 */
library RouterLib {
    error RouterLib__ZeroAmount();
    error RouterLib__InsufficientAllowance(uint256 allowance, uint256 amount);

    /**
     * @dev Returns the slot for the allowance of a token for a sender from an address.
     */
    function getAllowanceSlot(
        mapping(bytes32 key => uint256) storage allowances,
        address token,
        address sender,
        address from
    ) internal pure returns (bytes32 s) {
        assembly ("memory-safe") {
            mstore(0, shl(96, token))
            mstore(20, shl(96, sender))

            // Overwrite the last 8 bytes of the free memory pointer with zero,
            //which should always be zeros
            mstore(40, shl(96, from))

            let key := keccak256(0, 60)

            mstore(0, key)
            mstore(32, allowances.slot)

            s := keccak256(0, 64)
        }
    }

    /**
     * @dev Validates the allowance of a token for a sender from an address, and transfers the token.
     *
     * Requirements:
     * - The allowance must be greater than or equal to the amount.
     * - The amount must be greater than zero.
     * - If from is not the router, the token must have been approved for the router.
     */
    function validateAndTransfer(mapping(bytes32 key => uint256) storage allowances) internal {
        address token;
        address from;
        address to;
        uint256 amount;
        uint256 allowance;

        uint256 success;
        assembly ("memory-safe") {
            token := shr(96, calldataload(4))
            from := shr(96, calldataload(24))
            to := shr(96, calldataload(44))
            amount := calldataload(64)
        }

        bytes32 allowanceSlot = getAllowanceSlot(allowances, token, msg.sender, from);

        assembly ("memory-safe") {
            allowance := sload(allowanceSlot)

            if iszero(lt(allowance, amount)) {
                success := 1

                sstore(allowanceSlot, sub(allowance, amount))
            }
        }

        if (amount == 0) revert RouterLib__ZeroAmount(); // Also prevent calldata <= 64
        if (success == 0) revert RouterLib__InsufficientAllowance(allowance, amount);

        from == address(this) ? TokenLib.transfer(token, to, amount) : TokenLib.transferFrom(token, from, to, amount);
    }

    /**
     * @dev Calls the router to transfer tokens from an account to another account.
     *
     * Requirements:
     * - The call must succeed.
     * - The target contract must use `validateAndTransfer` inside its fallback function to validate the allowance
     *   and transfer the tokens accordingly.
     */
    function transfer(address router, address token, address from, address to, uint256 amount) internal {
        assembly ("memory-safe") {
            let m0x40 := mload(0x40)

            mstore(0, shr(32, shl(96, token)))
            mstore(24, shl(96, from))
            mstore(44, shl(96, to))
            mstore(64, amount)

            if iszero(call(gas(), router, 0, 0, 96, 0, 0)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }

            mstore(0x40, m0x40)
        }
    }

    /**
     * @dev Swaps tokens using the router logic.
     * It will also set the allowance for the logic contract to spend the token from the sender and reset it
     * after the swap is done.
     *
     * Requirements:
     * - The logic contract must not be the zero address.
     * - The call must succeed.
     * - The logic contract must call this contract's fallback function to validate the allowance and transfer the tokens.
     */
    function swap(
        mapping(bytes32 key => uint256) storage allowances,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address from,
        address to,
        bytes calldata route,
        bool exactIn,
        address logic
    ) internal returns (uint256 totalIn, uint256 totalOut) {
        bytes32 allowanceSlot = getAllowanceSlot(allowances, tokenIn, logic, from);

        uint256 length = 256 + route.length; // 32 * 6 + 32 + 32 + route.length
        bytes memory data = new bytes(length);

        assembly ("memory-safe") {
            sstore(allowanceSlot, amountIn)

            switch exactIn
            // swapExactIn(tokenIn, tokenOut, amountIn, amountOut, from, to, route)
            // swapExactOut(tokenIn, tokenOut, amountOut, amountIn, from, to, route)
            case 1 { mstore(data, 0xbd084435) }
            default { mstore(data, 0xcb7e0007) }

            mstore(add(data, 32), tokenIn)
            mstore(add(data, 64), tokenOut)
            mstore(add(data, 96), amountIn)
            mstore(add(data, 128), amountOut)
            mstore(add(data, 160), from)
            mstore(add(data, 192), to)
            mstore(add(data, 224), 224) // 32 * 6 + 32
            mstore(add(data, 256), route.length)
            calldatacopy(add(data, 288), route.offset, route.length)

            if iszero(call(gas(), logic, 0, add(data, 28), add(length, 4), 0, 64)) {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }

            totalIn := mload(0)
            totalOut := mload(32)

            sstore(allowanceSlot, 0)
        }
    }
}

File 7 of 9 : IRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IRouter {
    error Router__DeadlineExceeded();
    error Router__InsufficientOutputAmount(uint256 outputAmount, uint256 minOutputAmount);
    error Router__InsufficientAmountReceived(uint256 balanceBefore, uint256 balanceAfter, uint256 amountOutMin);
    error Router__InvalidTo();
    error Router__ZeroAmount();
    error Router__OnlyWnative();
    error Router__InvalidWnative();
    error Router__IdenticalTokens();
    error Router__LogicAlreadyAdded(address routerLogic);
    error Router__LogicNotFound(address routerLogic);
    error Router__UntrustedLogic(address routerLogic);
    error Router__Simulations(uint256[] amounts);
    error Router__SimulateSingle(uint256 amount);

    event SwapExactIn(
        address indexed sender, address to, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut
    );
    event SwapExactOut(
        address indexed sender, address to, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut
    );
    event RouterLogicUpdated(address indexed routerLogic, bool added);

    function WNATIVE() external view returns (address);
    function getTrustedLogicAt(uint256 index) external view returns (address);
    function getTrustedLogicLength() external view returns (uint256);
    function updateRouterLogic(address routerLogic, bool added) external;
    function swapExactIn(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOutMin,
        address to,
        uint256 deadline,
        bytes memory route
    ) external payable returns (uint256, uint256);
    function swapExactOut(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountOut,
        uint256 amountInMax,
        address to,
        uint256 deadline,
        bytes memory route
    ) external payable returns (uint256, uint256);
    function simulate(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address to,
        bool exactIn,
        bytes[] calldata route
    ) external payable;
    function simulateSingle(
        address logic,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut,
        address to,
        bool exactIn,
        bytes calldata route
    ) external payable;
}

File 8 of 9 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 9 of 9 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "remappings": [
    "@forge-std/contracts/=lib/forge-std/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"wnative","type":"address"},{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RouterLib__InsufficientAllowance","type":"error"},{"inputs":[],"name":"RouterLib__ZeroAmount","type":"error"},{"inputs":[],"name":"Router__DeadlineExceeded","type":"error"},{"inputs":[],"name":"Router__IdenticalTokens","type":"error"},{"inputs":[{"internalType":"uint256","name":"balanceBefore","type":"uint256"},{"internalType":"uint256","name":"balanceAfter","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"Router__InsufficientAmountReceived","type":"error"},{"inputs":[{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"name":"Router__InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"Router__InvalidTo","type":"error"},{"inputs":[],"name":"Router__InvalidWnative","type":"error"},{"inputs":[{"internalType":"address","name":"routerLogic","type":"address"}],"name":"Router__LogicAlreadyAdded","type":"error"},{"inputs":[{"internalType":"address","name":"routerLogic","type":"address"}],"name":"Router__LogicNotFound","type":"error"},{"inputs":[],"name":"Router__OnlyWnative","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Router__SimulateSingle","type":"error"},{"inputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"Router__Simulations","type":"error"},{"inputs":[{"internalType":"address","name":"routerLogic","type":"address"}],"name":"Router__UntrustedLogic","type":"error"},{"inputs":[],"name":"Router__ZeroAmount","type":"error"},{"inputs":[],"name":"TokenLib__BalanceOfFailed","type":"error"},{"inputs":[],"name":"TokenLib__NativeTransferFailed","type":"error"},{"inputs":[],"name":"TokenLib__TransferFailed","type":"error"},{"inputs":[],"name":"TokenLib__TransferFromFailed","type":"error"},{"inputs":[],"name":"TokenLib__UnwrapFailed","type":"error"},{"inputs":[],"name":"TokenLib__WrapFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"routerLogic","type":"address"},{"indexed":false,"internalType":"bool","name":"added","type":"bool"}],"name":"RouterLogicUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"SwapExactIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"SwapExactOut","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"WNATIVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getTrustedLogicAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTrustedLogicLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactIn","type":"bool"},{"internalType":"bytes[]","name":"multiRoutes","type":"bytes[]"}],"name":"simulate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactIn","type":"bool"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"simulateSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"swapExactIn","outputs":[{"internalType":"uint256","name":"totalIn","type":"uint256"},{"internalType":"uint256","name":"totalOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"route","type":"bytes"}],"name":"swapExactOut","outputs":[{"internalType":"uint256","name":"totalIn","type":"uint256"},{"internalType":"uint256","name":"totalOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"bool","name":"add","type":"bool"}],"name":"updateRouterLogic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a03461014a57601f620018d638819003918201601f19168301916001600160401b0383118484101761014f57808492604094855283398101031261014a57602061004982610165565b916001600160a01b0391829161005f9101610165565b1680156101315760018060a01b0319918260015416600155816000549384161760005560405192167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36001600255813b15610122575060805260405161175c90816200017a82396080518181816101b901528181610370015281816104e10152818161058b015281816105fb01528181610864015281816109c601528181610a5201528181610aa901528181610b6401528181610cd30152610d410152f35b632cac3e4f60e21b8152600490fd5b604051631e4fbdf760e01b815260006004820152602490fd5b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361014a5756fe60808060405260043610156101fb575b5036156101b757346101b25760006060600435811c91601835821c91602c35811c926040359261006282338860601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b90815491858310156101a4575b508415610192571561017457503081036100fd5750506040519163a9059cbb600052602052604052602060006044601c82865af13d9060005192604052156100dc576100d157503b155b6100bf57005b6040516321f1bb1f60e21b8152600490fd5b6001915014156100b9565b3d6100f3576040516321f1bb1f60e21b8152600490fd5b3d6000803e3d6000fd5b9091604051938351926323b872dd6000526020526040528252602060006064601c82885af1903d9260005194604052521561015d5761015257503b155b61014057005b604051633b4add1d60e11b8152600490fd5b60019150141561013a565b3d6100f357604051633b4add1d60e11b8152600490fd5b604490846040519163c67b4be360e01b835260048301526024820152fd5b604051630abd906360e21b8152600490fd5b85830390555060013861006f565b600080fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036101e957005b60405163589a15c360e01b8152600490fd5b60003560e01c908163470a2fd0146111c45750806354f461a1146111a6578063715018a61461114157806379ba5097146110b85780638da5cb5b1461108f578063a4b77eb914610d70578063b381cf4014610d2b578063c7a3e3ce14610b04578063cfc6cb69146107bb578063de55a527146106c3578063e30c39781461069a578063f1910f70146103075763f2fde38b14610297573861000f565b346101b25760203660031901126101b2576102b061121d565b6102b861132c565b60018060a01b0380911690816bffffffffffffffffffffffff60a01b6001541617600155600054167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700600080a3005b610310366112b2565b939796916103219693959196611377565b811561066b575b61033490868a8461156f565b8196339660018060a01b038216610358816000526004602052604060002054151590565b1561065357506001600160a01b03851661064a5730987f0000000000000000000000000000000000000000000000000000000000000000925b6001600160a01b038616156105f6575b6001600160a01b03828116908516146105e4576103be8b856116a5565b976103ec8b838560601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b938161010001610100116105ce5781908e61040a61010084016113e8565b95604051966104199088611398565b610100840180885261042a906113e8565b6020880190601f19013682378a895563bd08443588525287604087015288606087015260808601528c60a08601528d60c086015260e0850160e09052816101008601526101208501376101040191601c01915a9260008093604095f1156100f3576040997fd9a8cfa901e597f6bbb7ea94478cf9ad6f38d0dc3fd24d493e99cb40692e39f1966000519a60006020519455838a3060018060a01b038416146000146105bb5750506104da946115ea565b95610505877f00000000000000000000000000000000000000000000000000000000000000006116ee565b61050f87876116c5565b6001600160a01b031630036105b45786810380610585575b3401035b80610575575b5086516001600160a01b0394851681529084166020820152921660408301526060820184905260808201839052339160a090a2600160025582519182526020820152f35b61057f90336116c5565b87610531565b6105af817f00000000000000000000000000000000000000000000000000000000000000006116ee565b610527565b503461052b565b915093506105c8946115ea565b9561050f565b634e487b7160e01b600052601160045260246000fd5b60405163e454f9b760e01b8152600490fd5b9850507f0000000000000000000000000000000000000000000000000000000000000000309863d0e30db06000526000806004601c88865af16103a1573d6100f35760405163dc0c8cd160e01b8152600490fd5b86988592610391565b602490604051906394fad8f160e01b82526004820152fd5b90506001600160a01b03821661068857610334345b919050610328565b6103346106953384611656565b610680565b346101b25760003660031901126101b2576001546040516001600160a01b039091168152602090f35b346101b25760403660031901126101b2576106dc61121d565b60243590811515918281036101b2576106f361132c565b15610761576001600160a01b03811661070b81611404565b15610749575060207f25e48677e09b350ea4357542e7ea3d9b4a6665edbc68a909f93ed335dce512f6915b6040519384526001600160a01b031692a2005b6024906040519063070c6e8360e31b82526004820152fd5b6001600160a01b03811661077481611486565b156107a3575060207f25e48677e09b350ea4357542e7ea3d9b4a6665edbc68a909f93ed335dce512f691610736565b60249060405190630c10f95960e41b82526004820152fd5b6101003660031901126101b2576107d061121d565b6107d8611233565b906107e1611249565b906107ea61125f565b916107f3611275565b9060e43567ffffffffffffffff81116101b257610814903690600401611284565b939095610827428760843560643561156f565b8094339360018060a01b03841661084b816000526004602052604060002054151590565b1561065357506001600160a01b038116610afb575030957f0000000000000000000000000000000000000000000000000000000000000000925b6001600160a01b031615610aa4575b6001600160a01b03818116908416146105e4576108b187846116a5565b986108df86868460601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b948361010001610100116105ce576000601c61010486808c968e86998d61090b60409d610100016113e8565b9a6109188e519c8d611398565b6101008601808d52610929906113e8565b60208d019290601f19013684376064359055600114610a985763cb7e00078b525b528b8b8a015260643560608a015260843560808a01528d60a08a015260c089015260e08089015281610100890152610120880137019301915af1156100f3576024966000519560006020519455833060018060a01b03831614600014610a815750916109ef93916109be93608435926115ea565b80956109ea827f00000000000000000000000000000000000000000000000000000000000000006116ee565b6116c5565b6001600160a01b03163003610a7b5760643582900380610a4c575b606435903401035b80610a3c575b5015610a3557505b60405190634e37d9e560e01b82526004820152fd5b9050610a20565b610a4690336116c5565b84610a18565b610a76817f00000000000000000000000000000000000000000000000000000000000000006116ee565b610a0a565b34610a12565b935050610a929396608435926115ea565b926109ef565b63bd0844358b5261094a565b5092507f000000000000000000000000000000000000000000000000000000000000000092309363d0e30db06000526000806004601c606435855af1610894573d6100f35760405163dc0c8cd160e01b8152600490fd5b95879692610885565b610b28610b10366112b2565b9498909692959391610b20611377565b868a8461156f565b8196339660018060a01b038216610b4c816000526004602052604060002054151590565b1561065357506001600160a01b038516610d225730987f0000000000000000000000000000000000000000000000000000000000000000925b6001600160a01b03861615610cce575b6001600160a01b03828116908516146105e457610bb28b856116a5565b97610be08b838560601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b938161010001610100116105ce5781908e610bfe61010084016113e8565b9560405196610c0d9088611398565b6101008401808852610c1e906113e8565b6020880190601f19013682378a895563cb7e000788525287604087015288606087015260808601528c60a08601528d60c086015260e0850160e09052816101008601526101208501376101040191601c01915a9260008093604095f1156100f3576040997fbdf9df8586c933e26c968397ba74608d4b9accd48f470ef60ec2d8b98067e5b2966000519a60006020519455838a3060018060a01b038416146000146105bb5750506104da946115ea565b9850507f0000000000000000000000000000000000000000000000000000000000000000309863d0e30db06000526000806004601c88865af1610b95573d6100f35760405163dc0c8cd160e01b8152600490fd5b86988592610b85565b346101b25760003660031901126101b2576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b6101003660031901126101b257610d8561121d565b610d8d611233565b610d95611249565b610d9d61125f565b610da5611275565b9267ffffffffffffffff60e435116101b25736602360e4350112156101b25767ffffffffffffffff60e43560040135116101b25736602460e4356004013560051b60e4350101116101b257610dff60e435600401356113d0565b94610e0d6040519687611398565b600460e4350135808752601f1990610e24906113d0565b013660208801376000936001600160a01b035b60e435600401358610610e9757876040518091635f61f1fd60e11b82526024820160206004840152815180915260206044840192019060005b818110610e7e575050500390fd5b8251845285945060209384019390920191600101610e70565b8560001981146105ce57600101809660e435600401358110156110495760421960e43536030160248260051b60e43501013512156101b25760249060051b60e43501013560e4350167ffffffffffffffff6024820135116101b2576024810135360360448201136101b25760008091610f9b6040519163cfc6cb6960e01b60208401528689166024840152868a1660448401528688166064840152606435608484015260843560a4840152868b1660c48401528c151560e4840152610100610104840152610124602482013581850152836101449260248101356044820185840137602401358181018401879052601f01601f191681010390810184520182611398565b602081519101305af4503d15611088573d610fb5816113e8565b90610fc36040519283611398565b81523d6000602083013e5b805160208201516001600160e01b03198116919060048210611068575b50506001600160e01b031916634e37d9e560e01b0361101457602401519060051b890152610e37565b50871561105f576000905b806000198101116105ce57895160001982011015611049576000190160051b890160200152610e37565b634e487b7160e01b600052603260045260246000fd5b6000199061101f565b6001600160e01b031960049290920360031b82901b161690508b80610feb565b6060610fce565b346101b25760003660031901126101b2576000546040516001600160a01b039091168152602090f35b346101b25760003660031901126101b2576001546001600160a01b033381831603611129576bffffffffffffffffffffffff60a01b8092166001556000549133908316176000553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405163118cdaa760e01b8152336004820152602490fd5b346101b25760003660031901126101b25761115a61132c565b600180546001600160a01b0319908116909155600080549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101b25760003660031901126101b2576020600354604051908152f35b346101b25760203660031901126101b257600435906003548210156110495760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b909101546001600160a01b03168152602090f35b600435906001600160a01b03821682036101b257565b602435906001600160a01b03821682036101b257565b604435906001600160a01b03821682036101b257565b60a435906001600160a01b03821682036101b257565b60c4359081151582036101b257565b9181601f840112156101b25782359167ffffffffffffffff83116101b257602083818601950101116101b257565b906101006003198301126101b2576001600160a01b039060043582811681036101b2579260243583811681036101b2579260443581811681036101b25792606435926084359260a43590811681036101b2579160c4359160e4359067ffffffffffffffff82116101b25761132891600401611284565b9091565b6000546001600160a01b0316330361112957565b6003548110156110495760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b60028054146113865760028055565b604051633ee5aeb560e01b8152600490fd5b90601f8019910116810190811067ffffffffffffffff8211176113ba57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116113ba5760051b60200190565b67ffffffffffffffff81116113ba57601f01601f191660200190565b600081815260046020526040812054611481576003546801000000000000000081101561146d57908261145961144284600160409601600355611340565b819391549060031b91821b91600019901b19161790565b905560035492815260046020522055600190565b634e487b7160e01b82526041600452602482fd5b905090565b6000908082526004908160205260408320548015156000146115695760001990808201818111611556576003549083820191821161154357818103611510575b50505060035480156114fd578101906114de82611340565b909182549160031b1b1916905560035582526020526040812055600190565b634e487b7160e01b855260318452602485fd5b61152e61151f61144293611340565b90549060031b1c928392611340565b905585528360205260408520553880806114c6565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b865260118552602486fd5b50505090565b909290916001600160a01b031680159081156115e0575b506115ce5742116115bc57159081156115b3575b506115a157565b6040516398bbadf560e01b8152600490fd5b9050153861159a565b604051632e7d087f60e21b8152600490fd5b60405163c9d3e5fb60e01b8152600490fd5b9050301438611586565b9091938381106116385750906115ff916116a5565b908083018084116105ce57821061161557500390565b6064929160405192636d72bca560e11b8452600484015260248301526044820152fd5b6044908460405191638de8583f60e01b835260048301526024820152fd5b91906020906024601c60009586936370a08231855285525afa8251923d9115611696575b5060201161168457565b6040516301f8168360e21b8152600490fd5b3d1561167a575b3d81803e3d90fd5b6001600160a01b0381166116b857503190565b906116c291611656565b90565b60008080809481945af1156116d75750565b3d61169d5760405163500da30360e11b8152600490fd5b601c9160246000938480948194632e1a7d4d83526020525af11561170f5750565b3d61169d5760405163028e458f60e61b8152600490fdfea264697066735822122024912bdfea342d4cb80e7c261aacc6193b21381a51607c9c8f109393f5df3f1e64736f6c63430008140033000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7000000000000000000000000f961ee51015b1efb4461d40d1f6b58a7832e931d

Deployed Bytecode

0x60808060405260043610156101fb575b5036156101b757346101b25760006060600435811c91601835821c91602c35811c926040359261006282338860601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b90815491858310156101a4575b508415610192571561017457503081036100fd5750506040519163a9059cbb600052602052604052602060006044601c82865af13d9060005192604052156100dc576100d157503b155b6100bf57005b6040516321f1bb1f60e21b8152600490fd5b6001915014156100b9565b3d6100f3576040516321f1bb1f60e21b8152600490fd5b3d6000803e3d6000fd5b9091604051938351926323b872dd6000526020526040528252602060006064601c82885af1903d9260005194604052521561015d5761015257503b155b61014057005b604051633b4add1d60e11b8152600490fd5b60019150141561013a565b3d6100f357604051633b4add1d60e11b8152600490fd5b604490846040519163c67b4be360e01b835260048301526024820152fd5b604051630abd906360e21b8152600490fd5b85830390555060013861006f565b600080fd5b7f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b031633036101e957005b60405163589a15c360e01b8152600490fd5b60003560e01c908163470a2fd0146111c45750806354f461a1146111a6578063715018a61461114157806379ba5097146110b85780638da5cb5b1461108f578063a4b77eb914610d70578063b381cf4014610d2b578063c7a3e3ce14610b04578063cfc6cb69146107bb578063de55a527146106c3578063e30c39781461069a578063f1910f70146103075763f2fde38b14610297573861000f565b346101b25760203660031901126101b2576102b061121d565b6102b861132c565b60018060a01b0380911690816bffffffffffffffffffffffff60a01b6001541617600155600054167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700600080a3005b610310366112b2565b939796916103219693959196611377565b811561066b575b61033490868a8461156f565b8196339660018060a01b038216610358816000526004602052604060002054151590565b1561065357506001600160a01b03851661064a5730987f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7925b6001600160a01b038616156105f6575b6001600160a01b03828116908516146105e4576103be8b856116a5565b976103ec8b838560601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b938161010001610100116105ce5781908e61040a61010084016113e8565b95604051966104199088611398565b610100840180885261042a906113e8565b6020880190601f19013682378a895563bd08443588525287604087015288606087015260808601528c60a08601528d60c086015260e0850160e09052816101008601526101208501376101040191601c01915a9260008093604095f1156100f3576040997fd9a8cfa901e597f6bbb7ea94478cf9ad6f38d0dc3fd24d493e99cb40692e39f1966000519a60006020519455838a3060018060a01b038416146000146105bb5750506104da946115ea565b95610505877f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76116ee565b61050f87876116c5565b6001600160a01b031630036105b45786810380610585575b3401035b80610575575b5086516001600160a01b0394851681529084166020820152921660408301526060820184905260808201839052339160a090a2600160025582519182526020820152f35b61057f90336116c5565b87610531565b6105af817f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76116ee565b610527565b503461052b565b915093506105c8946115ea565b9561050f565b634e487b7160e01b600052601160045260246000fd5b60405163e454f9b760e01b8152600490fd5b9850507f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7309863d0e30db06000526000806004601c88865af16103a1573d6100f35760405163dc0c8cd160e01b8152600490fd5b86988592610391565b602490604051906394fad8f160e01b82526004820152fd5b90506001600160a01b03821661068857610334345b919050610328565b6103346106953384611656565b610680565b346101b25760003660031901126101b2576001546040516001600160a01b039091168152602090f35b346101b25760403660031901126101b2576106dc61121d565b60243590811515918281036101b2576106f361132c565b15610761576001600160a01b03811661070b81611404565b15610749575060207f25e48677e09b350ea4357542e7ea3d9b4a6665edbc68a909f93ed335dce512f6915b6040519384526001600160a01b031692a2005b6024906040519063070c6e8360e31b82526004820152fd5b6001600160a01b03811661077481611486565b156107a3575060207f25e48677e09b350ea4357542e7ea3d9b4a6665edbc68a909f93ed335dce512f691610736565b60249060405190630c10f95960e41b82526004820152fd5b6101003660031901126101b2576107d061121d565b6107d8611233565b906107e1611249565b906107ea61125f565b916107f3611275565b9060e43567ffffffffffffffff81116101b257610814903690600401611284565b939095610827428760843560643561156f565b8094339360018060a01b03841661084b816000526004602052604060002054151590565b1561065357506001600160a01b038116610afb575030957f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7925b6001600160a01b031615610aa4575b6001600160a01b03818116908416146105e4576108b187846116a5565b986108df86868460601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b948361010001610100116105ce576000601c61010486808c968e86998d61090b60409d610100016113e8565b9a6109188e519c8d611398565b6101008601808d52610929906113e8565b60208d019290601f19013684376064359055600114610a985763cb7e00078b525b528b8b8a015260643560608a015260843560808a01528d60a08a015260c089015260e08089015281610100890152610120880137019301915af1156100f3576024966000519560006020519455833060018060a01b03831614600014610a815750916109ef93916109be93608435926115ea565b80956109ea827f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76116ee565b6116c5565b6001600160a01b03163003610a7b5760643582900380610a4c575b606435903401035b80610a3c575b5015610a3557505b60405190634e37d9e560e01b82526004820152fd5b9050610a20565b610a4690336116c5565b84610a18565b610a76817f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76116ee565b610a0a565b34610a12565b935050610a929396608435926115ea565b926109ef565b63bd0844358b5261094a565b5092507f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c792309363d0e30db06000526000806004601c606435855af1610894573d6100f35760405163dc0c8cd160e01b8152600490fd5b95879692610885565b610b28610b10366112b2565b9498909692959391610b20611377565b868a8461156f565b8196339660018060a01b038216610b4c816000526004602052604060002054151590565b1561065357506001600160a01b038516610d225730987f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7925b6001600160a01b03861615610cce575b6001600160a01b03828116908516146105e457610bb28b856116a5565b97610be08b838560601b60005260601b60145260601b602852603c6000206000526005602052604060002090565b938161010001610100116105ce5781908e610bfe61010084016113e8565b9560405196610c0d9088611398565b6101008401808852610c1e906113e8565b6020880190601f19013682378a895563cb7e000788525287604087015288606087015260808601528c60a08601528d60c086015260e0850160e09052816101008601526101208501376101040191601c01915a9260008093604095f1156100f3576040997fbdf9df8586c933e26c968397ba74608d4b9accd48f470ef60ec2d8b98067e5b2966000519a60006020519455838a3060018060a01b038416146000146105bb5750506104da946115ea565b9850507f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7309863d0e30db06000526000806004601c88865af1610b95573d6100f35760405163dc0c8cd160e01b8152600490fd5b86988592610b85565b346101b25760003660031901126101b2576040517f000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c76001600160a01b03168152602090f35b6101003660031901126101b257610d8561121d565b610d8d611233565b610d95611249565b610d9d61125f565b610da5611275565b9267ffffffffffffffff60e435116101b25736602360e4350112156101b25767ffffffffffffffff60e43560040135116101b25736602460e4356004013560051b60e4350101116101b257610dff60e435600401356113d0565b94610e0d6040519687611398565b600460e4350135808752601f1990610e24906113d0565b013660208801376000936001600160a01b035b60e435600401358610610e9757876040518091635f61f1fd60e11b82526024820160206004840152815180915260206044840192019060005b818110610e7e575050500390fd5b8251845285945060209384019390920191600101610e70565b8560001981146105ce57600101809660e435600401358110156110495760421960e43536030160248260051b60e43501013512156101b25760249060051b60e43501013560e4350167ffffffffffffffff6024820135116101b2576024810135360360448201136101b25760008091610f9b6040519163cfc6cb6960e01b60208401528689166024840152868a1660448401528688166064840152606435608484015260843560a4840152868b1660c48401528c151560e4840152610100610104840152610124602482013581850152836101449260248101356044820185840137602401358181018401879052601f01601f191681010390810184520182611398565b602081519101305af4503d15611088573d610fb5816113e8565b90610fc36040519283611398565b81523d6000602083013e5b805160208201516001600160e01b03198116919060048210611068575b50506001600160e01b031916634e37d9e560e01b0361101457602401519060051b890152610e37565b50871561105f576000905b806000198101116105ce57895160001982011015611049576000190160051b890160200152610e37565b634e487b7160e01b600052603260045260246000fd5b6000199061101f565b6001600160e01b031960049290920360031b82901b161690508b80610feb565b6060610fce565b346101b25760003660031901126101b2576000546040516001600160a01b039091168152602090f35b346101b25760003660031901126101b2576001546001600160a01b033381831603611129576bffffffffffffffffffffffff60a01b8092166001556000549133908316176000553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b60405163118cdaa760e01b8152336004820152602490fd5b346101b25760003660031901126101b25761115a61132c565b600180546001600160a01b0319908116909155600080549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101b25760003660031901126101b2576020600354604051908152f35b346101b25760203660031901126101b257600435906003548210156110495760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b909101546001600160a01b03168152602090f35b600435906001600160a01b03821682036101b257565b602435906001600160a01b03821682036101b257565b604435906001600160a01b03821682036101b257565b60a435906001600160a01b03821682036101b257565b60c4359081151582036101b257565b9181601f840112156101b25782359167ffffffffffffffff83116101b257602083818601950101116101b257565b906101006003198301126101b2576001600160a01b039060043582811681036101b2579260243583811681036101b2579260443581811681036101b25792606435926084359260a43590811681036101b2579160c4359160e4359067ffffffffffffffff82116101b25761132891600401611284565b9091565b6000546001600160a01b0316330361112957565b6003548110156110495760036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0190600090565b60028054146113865760028055565b604051633ee5aeb560e01b8152600490fd5b90601f8019910116810190811067ffffffffffffffff8211176113ba57604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116113ba5760051b60200190565b67ffffffffffffffff81116113ba57601f01601f191660200190565b600081815260046020526040812054611481576003546801000000000000000081101561146d57908261145961144284600160409601600355611340565b819391549060031b91821b91600019901b19161790565b905560035492815260046020522055600190565b634e487b7160e01b82526041600452602482fd5b905090565b6000908082526004908160205260408320548015156000146115695760001990808201818111611556576003549083820191821161154357818103611510575b50505060035480156114fd578101906114de82611340565b909182549160031b1b1916905560035582526020526040812055600190565b634e487b7160e01b855260318452602485fd5b61152e61151f61144293611340565b90549060031b1c928392611340565b905585528360205260408520553880806114c6565b634e487b7160e01b875260118652602487fd5b634e487b7160e01b865260118552602486fd5b50505090565b909290916001600160a01b031680159081156115e0575b506115ce5742116115bc57159081156115b3575b506115a157565b6040516398bbadf560e01b8152600490fd5b9050153861159a565b604051632e7d087f60e21b8152600490fd5b60405163c9d3e5fb60e01b8152600490fd5b9050301438611586565b9091938381106116385750906115ff916116a5565b908083018084116105ce57821061161557500390565b6064929160405192636d72bca560e11b8452600484015260248301526044820152fd5b6044908460405191638de8583f60e01b835260048301526024820152fd5b91906020906024601c60009586936370a08231855285525afa8251923d9115611696575b5060201161168457565b6040516301f8168360e21b8152600490fd5b3d1561167a575b3d81803e3d90fd5b6001600160a01b0381166116b857503190565b906116c291611656565b90565b60008080809481945af1156116d75750565b3d61169d5760405163500da30360e11b8152600490fd5b601c9160246000938480948194632e1a7d4d83526020525af11561170f5750565b3d61169d5760405163028e458f60e61b8152600490fdfea264697066735822122024912bdfea342d4cb80e7c261aacc6193b21381a51607c9c8f109393f5df3f1e64736f6c63430008140033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7000000000000000000000000f961ee51015b1efb4461d40d1f6b58a7832e931d

-----Decoded View---------------
Arg [0] : wnative (address): 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
Arg [1] : initialOwner (address): 0xF961ee51015b1EfB4461D40D1f6b58a7832E931D

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b31f66aa3c1e785363f0875a1b74e27b85fd66c7
Arg [1] : 000000000000000000000000f961ee51015b1efb4461d40d1f6b58a7832e931d


Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.