ETH Price: $3,279.24 (-1.83%)

Contract

0x0000000000489d89D2B233D3375C045dfD05745F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00
Transaction Hash
Method
Block
From
To
Bridge209650282024-10-14 16:34:3569 days ago1728923675IN
0x00000000...dfD05745F
0.4 ETH0.0024543730.51906746
Bridge209106672024-10-07 2:22:5977 days ago1728267779IN
0x00000000...dfD05745F
0.08940586 ETH0.0009883212.28933747
Bridge208893182024-10-04 2:58:5980 days ago1728010739IN
0x00000000...dfD05745F
0 ETH0.000617275.07184076
Bridge208408302024-09-27 8:41:3586 days ago1727426495IN
0x00000000...dfD05745F
0.02 ETH0.0009675212.04155475
Bridge208406162024-09-27 7:58:2386 days ago1727423903IN
0x00000000...dfD05745F
0.028 ETH0.001039812.94116325
Bridge208406072024-09-27 7:56:3586 days ago1727423795IN
0x00000000...dfD05745F
0 ETH0.001473112.10250396
Bridge208169822024-09-24 0:51:3590 days ago1727139095IN
0x00000000...dfD05745F
0.09 ETH0.0017457621.71426316
Bridge207775402024-09-18 12:41:2395 days ago1726663283IN
0x00000000...dfD05745F
0.332 ETH0.00049096.10423495
Bridge206934822024-09-06 18:56:35107 days ago1725648995IN
0x00000000...dfD05745F
1.42 ETH0.0009007111.2
Bridge206311962024-08-29 2:14:23116 days ago1724897663IN
0x00000000...dfD05745F
0.18851613 ETH0.000063520.78980957
Bridge205317702024-08-15 4:53:59130 days ago1723697639IN
0x00000000...dfD05745F
0.00547837 ETH0.000232792.89508472
Bridge204895052024-08-09 7:19:35135 days ago1723187975IN
0x00000000...dfD05745F
75 ETH0.000223742.78094203
Bridge204724902024-08-06 22:23:23138 days ago1722983003IN
0x00000000...dfD05745F
0.82207845 ETH0.000282473.51190263
Bridge204698052024-08-06 13:23:23138 days ago1722950603IN
0x00000000...dfD05745F
0.0054 ETH0.00041645.1809228
Bridge204697882024-08-06 13:19:59138 days ago1722950399IN
0x00000000...dfD05745F
0.016 ETH0.000370924.61644169
Bridge204696612024-08-06 12:54:23138 days ago1722948863IN
0x00000000...dfD05745F
0 ETH0.000696675.50802575
Bridge204695542024-08-06 12:32:59138 days ago1722947579IN
0x00000000...dfD05745F
0.003 ETH0.00027953.47708124
Bridge204695232024-08-06 12:26:47138 days ago1722947207IN
0x00000000...dfD05745F
0 ETH0.000531634.04882184
Bridge204695082024-08-06 12:23:47138 days ago1722947027IN
0x00000000...dfD05745F
0.007 ETH0.000270133.36102873
Bridge204694752024-08-06 12:17:11138 days ago1722946631IN
0x00000000...dfD05745F
0.4 ETH0.000201082.50074294
Bridge204694392024-08-06 12:09:59138 days ago1722946199IN
0x00000000...dfD05745F
0.0003 ETH0.000247253.07683211
Bridge204694142024-08-06 12:04:59138 days ago1722945899IN
0x00000000...dfD05745F
0 ETH0.000341542.80652955
Bridge204693582024-08-06 11:53:47138 days ago1722945227IN
0x00000000...dfD05745F
0 ETH0.000353852.90775729
Bridge204691362024-08-06 11:09:23138 days ago1722942563IN
0x00000000...dfD05745F
1.15 ETH0.000239352.97674924
Bridge204690872024-08-06 10:59:35138 days ago1722941975IN
0x00000000...dfD05745F
0 ETH0.000377812.9870463
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
209650282024-10-14 16:34:3569 days ago1728923675
0x00000000...dfD05745F
0.4 ETH
209106672024-10-07 2:22:5977 days ago1728267779
0x00000000...dfD05745F
0.08940586 ETH
208408302024-09-27 8:41:3586 days ago1727426495
0x00000000...dfD05745F
0.02 ETH
208406162024-09-27 7:58:2386 days ago1727423903
0x00000000...dfD05745F
0.028 ETH
208169822024-09-24 0:51:3590 days ago1727139095
0x00000000...dfD05745F
0.09 ETH
207775402024-09-18 12:41:2395 days ago1726663283
0x00000000...dfD05745F
0.332 ETH
206934822024-09-06 18:56:35107 days ago1725648995
0x00000000...dfD05745F
1.42 ETH
206311962024-08-29 2:14:23116 days ago1724897663
0x00000000...dfD05745F
0.18851613 ETH
205317702024-08-15 4:53:59130 days ago1723697639
0x00000000...dfD05745F
0.00547837 ETH
204895052024-08-09 7:19:35135 days ago1723187975
0x00000000...dfD05745F
75 ETH
204724902024-08-06 22:23:23138 days ago1722983003
0x00000000...dfD05745F
0.82207845 ETH
204698052024-08-06 13:23:23138 days ago1722950603
0x00000000...dfD05745F
0.0054 ETH
204697882024-08-06 13:19:59138 days ago1722950399
0x00000000...dfD05745F
0.016 ETH
204695542024-08-06 12:32:59138 days ago1722947579
0x00000000...dfD05745F
0.003 ETH
204695082024-08-06 12:23:47138 days ago1722947027
0x00000000...dfD05745F
0.007 ETH
204694752024-08-06 12:17:11138 days ago1722946631
0x00000000...dfD05745F
0.4 ETH
204694392024-08-06 12:09:59138 days ago1722946199
0x00000000...dfD05745F
0.0003 ETH
204691362024-08-06 11:09:23138 days ago1722942563
0x00000000...dfD05745F
1.15 ETH
204689582024-08-06 10:33:47138 days ago1722940427
0x00000000...dfD05745F
0.45 ETH
204689532024-08-06 10:32:47138 days ago1722940367
0x00000000...dfD05745F
0.009 ETH
204689472024-08-06 10:31:35138 days ago1722940295
0x00000000...dfD05745F
0.35 ETH
204687852024-08-06 9:59:11138 days ago1722938351
0x00000000...dfD05745F
0.20840591 ETH
204687652024-08-06 9:55:11138 days ago1722938111
0x00000000...dfD05745F
0.02 ETH
204685932024-08-06 9:19:59138 days ago1722935999
0x00000000...dfD05745F
1.91 ETH
204685572024-08-06 9:12:47138 days ago1722935567
0x00000000...dfD05745F
0.21 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FastBridgeRouter

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 18 : FastBridgeRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {DefaultRouter} from "../router/DefaultRouter.sol";
import {UniversalTokenLib} from "../router/libs/UniversalToken.sol";
import {ActionLib, LimitedToken} from "../router/libs/Structs.sol";
import {IFastBridge} from "./interfaces/IFastBridge.sol";
import {IFastBridgeRouter, SwapQuery} from "./interfaces/IFastBridgeRouter.sol";
import {ISwapQuoter} from "./interfaces/ISwapQuoter.sol";

import {Ownable} from "@openzeppelin/contracts-4.5.0/access/Ownable.sol";

contract FastBridgeRouter is DefaultRouter, Ownable, IFastBridgeRouter {
    using UniversalTokenLib for address;

    /// @notice Emitted when the swap quoter is set.
    /// @param newSwapQuoter The new swap quoter.
    event SwapQuoterSet(address newSwapQuoter);

    /// @notice Emitted when the new FastBridge contract is set.
    /// @param newFastBridge The new FastBridge contract.
    event FastBridgeSet(address newFastBridge);

    /// @inheritdoc IFastBridgeRouter
    bytes1 public constant GAS_REBATE_FLAG = 0x2A;

    /// @inheritdoc IFastBridgeRouter
    address public fastBridge;
    /// @inheritdoc IFastBridgeRouter
    address public swapQuoter;

    constructor(address owner_) {
        transferOwnership(owner_);
    }

    /// @inheritdoc IFastBridgeRouter
    function setFastBridge(address fastBridge_) external onlyOwner {
        fastBridge = fastBridge_;
        emit FastBridgeSet(fastBridge_);
    }

    /// @inheritdoc IFastBridgeRouter
    function setSwapQuoter(address swapQuoter_) external onlyOwner {
        swapQuoter = swapQuoter_;
        emit SwapQuoterSet(swapQuoter_);
    }

    /// @inheritdoc IFastBridgeRouter
    function bridge(
        address recipient,
        uint256 chainId,
        address token,
        uint256 amount,
        SwapQuery memory originQuery,
        SwapQuery memory destQuery
    ) external payable {
        if (originQuery.hasAdapter()) {
            // Perform a swap using the swap adapter, set this contract as recipient
            (token, amount) = _doSwap(address(this), token, amount, originQuery);
        } else {
            // Otherwise, pull the token from the user to this contract
            amount = _pullToken(address(this), token, amount);
        }
        IFastBridge.BridgeParams memory params = IFastBridge.BridgeParams({
            dstChainId: uint32(chainId),
            sender: msg.sender,
            to: recipient,
            originToken: token,
            destToken: destQuery.tokenOut,
            originAmount: amount,
            destAmount: destQuery.minAmountOut,
            sendChainGas: _chainGasRequested(destQuery.rawParams),
            deadline: destQuery.deadline
        });
        token.universalApproveInfinity(fastBridge, amount);
        uint256 msgValue = token == UniversalTokenLib.ETH_ADDRESS ? amount : 0;
        IFastBridge(fastBridge).bridge{value: msgValue}(params);
    }

    /// @inheritdoc IFastBridgeRouter
    function getOriginAmountOut(
        address tokenIn,
        address[] memory rfqTokens,
        uint256 amountIn
    ) external view returns (SwapQuery[] memory originQueries) {
        uint256 len = rfqTokens.length;
        originQueries = new SwapQuery[](len);
        for (uint256 i = 0; i < len; ++i) {
            originQueries[i] = ISwapQuoter(swapQuoter).getAmountOut(
                LimitedToken({actionMask: ActionLib.allActions(), token: tokenIn}),
                rfqTokens[i],
                amountIn
            );
            // Adjust the Adapter address if it exists
            if (originQueries[i].hasAdapter()) {
                originQueries[i].routerAdapter = address(this);
            }
        }
    }

    /// @dev Checks if the explicit instruction to send gas to the destination chain was provided.
    function _chainGasRequested(bytes memory rawParams) internal pure returns (bool) {
        return rawParams.length > 0 && rawParams[0] == GAS_REBATE_FLAG;
    }
}

File 2 of 18 : DefaultRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {DefaultAdapter} from "./adapters/DefaultAdapter.sol";
import {IRouterAdapter} from "./interfaces/IRouterAdapter.sol";
import {DeadlineExceeded, InsufficientOutputAmount, MsgValueIncorrect, TokenNotETH} from "./libs/Errors.sol";
import {Action, DefaultParams, SwapQuery} from "./libs/Structs.sol";
import {UniversalTokenLib} from "./libs/UniversalToken.sol";

import {SafeERC20, IERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol";

/// @title DefaultRouter
/// @notice Base contract for all Synapse Routers, that is able to natively work with Default Pools
/// due to the fact that it inherits from DefaultAdapter.
abstract contract DefaultRouter is DefaultAdapter {
    using SafeERC20 for IERC20;
    using UniversalTokenLib for address;

    /// @dev Performs a "swap from tokenIn" following instructions from `query`.
    /// `query` will include the router adapter to use, and the exact type of "tokenIn -> tokenOut swap"
    /// should be encoded in `query.rawParams`.
    function _doSwap(
        address recipient,
        address tokenIn,
        uint256 amountIn,
        SwapQuery memory query
    ) internal returns (address tokenOut, uint256 amountOut) {
        // First, check the deadline for the swap
        // solhint-disable-next-line not-rely-on-time
        if (block.timestamp > query.deadline) revert DeadlineExceeded();
        // Pull initial token from the user to specified router adapter
        amountIn = _pullToken(query.routerAdapter, tokenIn, amountIn);
        tokenOut = query.tokenOut;
        address routerAdapter = query.routerAdapter;
        if (routerAdapter == address(this)) {
            // If the router adapter is this contract, we can perform the swap directly and trust the result
            amountOut = _adapterSwap(recipient, tokenIn, amountIn, tokenOut, query.rawParams);
        } else {
            // Otherwise, we need to call the router adapter. Adapters are permissionless, so we verify the result
            // Record tokenOut balance before swap
            amountOut = tokenOut.universalBalanceOf(recipient);
            IRouterAdapter(routerAdapter).adapterSwap{value: msg.value}({
                recipient: recipient,
                tokenIn: tokenIn,
                amountIn: amountIn,
                tokenOut: tokenOut,
                rawParams: query.rawParams
            });
            // Use the difference between the recorded balance and the current balance as the amountOut
            amountOut = tokenOut.universalBalanceOf(recipient) - amountOut;
        }
        // Finally, check that the recipient received at least as much as they wanted
        if (amountOut < query.minAmountOut) revert InsufficientOutputAmount();
    }

    /// @dev Pulls a requested token from the user to the requested recipient.
    /// Or, if msg.value was provided, check that ETH_ADDRESS was used and msg.value is correct.
    function _pullToken(
        address recipient,
        address token,
        uint256 amount
    ) internal returns (uint256 amountPulled) {
        if (msg.value == 0) {
            token.assertIsContract();
            // Record token balance before transfer
            amountPulled = IERC20(token).balanceOf(recipient);
            // Token needs to be pulled only if msg.value is zero
            // This way user can specify WETH as the origin asset
            IERC20(token).safeTransferFrom(msg.sender, recipient, amount);
            // Use the difference between the recorded balance and the current balance as the amountPulled
            amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;
        } else {
            // Otherwise, we need to check that ETH was specified
            if (token != UniversalTokenLib.ETH_ADDRESS) revert TokenNotETH();
            // And that amount matches msg.value
            if (amount != msg.value) revert MsgValueIncorrect();
            // We will forward msg.value in the external call later, if recipient is not this contract
            amountPulled = msg.value;
        }
    }
}

File 3 of 18 : UniversalToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {TokenNotContract} from "./Errors.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol";

library UniversalTokenLib {
    using SafeERC20 for IERC20;

    address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.
    /// @dev This might trigger fallback, if ETH is transferred to the contract.
    /// Make sure this can not lead to reentrancy attacks.
    function universalTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        // Don't do anything, if need to send tokens to this address
        if (to == address(this)) return;
        if (token == ETH_ADDRESS) {
            /// @dev Note: this can potentially lead to executing code in `to`.
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, ) = to.call{value: value}("");
            require(success, "ETH transfer failed");
        } else {
            IERC20(token).safeTransfer(to, value);
        }
    }

    /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient
    /// to spend the given amount.
    function universalApproveInfinity(
        address token,
        address spender,
        uint256 amountToSpend
    ) internal {
        // ETH Chad doesn't require your approval
        if (token == ETH_ADDRESS) return;
        // No-op if allowance is already sufficient
        uint256 allowance = IERC20(token).allowance(address(this), spender);
        if (allowance >= amountToSpend) return;
        // Otherwise, reset approval to 0 and set to max allowance
        if (allowance > 0) IERC20(token).safeApprove(spender, 0);
        IERC20(token).safeApprove(spender, type(uint256).max);
    }

    /// @notice Returns the balance of the given token (or native ETH) for the given account.
    function universalBalanceOf(address token, address account) internal view returns (uint256) {
        if (token == ETH_ADDRESS) {
            return account.balance;
        } else {
            return IERC20(token).balanceOf(account);
        }
    }

    /// @dev Checks that token is a contract and not ETH_ADDRESS.
    function assertIsContract(address token) internal view {
        // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)
        if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();
        // Check that token is not an EOA
        if (token.code.length == 0) revert TokenNotContract();
    }
}

File 4 of 18 : Structs.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13; // "using A for B global" requires 0.8.13 or higher

// ══════════════════════════════════════════ TOKEN AND POOL DESCRIPTION ═══════════════════════════════════════════════

/// @notice Struct representing a bridge token. Used as the return value in view functions.
/// @param symbol   Bridge token symbol: unique token ID consistent among all chains
/// @param token    Bridge token address
struct BridgeToken {
    string symbol;
    address token;
}

/// @notice Struct used by IPoolHandler to represent a token in a pool
/// @param index    Token index in the pool
/// @param token    Token address
struct IndexedToken {
    uint8 index;
    address token;
}

/// @notice Struct representing a token, and the available Actions for performing a swap.
/// @param actionMask   Bitmask representing what actions (see ActionLib) are available for swapping a token
/// @param token        Token address
struct LimitedToken {
    uint256 actionMask;
    address token;
}

/// @notice Struct representing how pool tokens are stored by `SwapQuoter`.
/// @param isWeth   Whether the token represents Wrapped ETH.
/// @param token    Token address.
struct PoolToken {
    bool isWeth;
    address token;
}

/// @notice Struct representing a liquidity pool. Used as the return value in view functions.
/// @param pool         Pool address.
/// @param lpToken      Address of pool's LP token.
/// @param tokens       List of pool's tokens.
struct Pool {
    address pool;
    address lpToken;
    PoolToken[] tokens;
}

// ════════════════════════════════════════════════ ROUTER STRUCTS ═════════════════════════════════════════════════════

/// @notice Struct representing a quote request for swapping a bridge token.
/// Used in destination chain's SynapseRouter, hence the name "Destination Request".
/// @dev tokenOut is passed externally.
/// @param symbol   Bridge token symbol: unique token ID consistent among all chains
/// @param amountIn Amount of bridge token to start with, before the bridge fee is applied
struct DestRequest {
    string symbol;
    uint256 amountIn;
}

/// @notice Struct representing a swap request for SynapseRouter.
/// @dev tokenIn is supplied separately.
/// @param routerAdapter    Contract that will perform the swap for the Router. Address(0) specifies a "no swap" query.
/// @param tokenOut         Token address to swap to.
/// @param minAmountOut     Minimum amount of tokens to receive after the swap, or tx will be reverted.
/// @param deadline         Latest timestamp for when the transaction needs to be executed, or tx will be reverted.
/// @param rawParams        ABI-encoded params for the swap that will be passed to `routerAdapter`.
///                         Should be DefaultParams for swaps via DefaultAdapter.
struct SwapQuery {
    address routerAdapter;
    address tokenOut;
    uint256 minAmountOut;
    uint256 deadline;
    bytes rawParams;
}

using SwapQueryLib for SwapQuery global;

library SwapQueryLib {
    /// @notice Checks whether the router adapter was specified in the query.
    /// Query without a router adapter specifies that no action needs to be taken.
    function hasAdapter(SwapQuery memory query) internal pure returns (bool) {
        return query.routerAdapter != address(0);
    }

    /// @notice Fills `routerAdapter` and `deadline` fields in query, if it specifies one of the supported Actions,
    /// and if a path for this action was found.
    function fillAdapterAndDeadline(SwapQuery memory query, address routerAdapter) internal pure {
        // Fill the fields only if some path was found.
        if (query.minAmountOut == 0) return;
        // Empty params indicates no action needs to be done, thus no adapter is needed.
        query.routerAdapter = query.rawParams.length == 0 ? address(0) : routerAdapter;
        // Set default deadline to infinity. Not using the value of 0,
        // which would lead to every swap to revert by default.
        query.deadline = type(uint256).max;
    }
}

// ════════════════════════════════════════════════ ADAPTER STRUCTS ════════════════════════════════════════════════════

/// @notice Struct representing parameters for swapping via DefaultAdapter.
/// @param action           Action that DefaultAdapter needs to perform.
/// @param pool             Liquidity pool that will be used for Swap/AddLiquidity/RemoveLiquidity actions.
/// @param tokenIndexFrom   Token index to swap from. Used for swap/addLiquidity actions.
/// @param tokenIndexTo     Token index to swap to. Used for swap/removeLiquidity actions.
struct DefaultParams {
    Action action;
    address pool;
    uint8 tokenIndexFrom;
    uint8 tokenIndexTo;
}

/// @notice All possible actions that DefaultAdapter could perform.
enum Action {
    Swap, // swap between two pools tokens
    AddLiquidity, // add liquidity in a form of a single pool token
    RemoveLiquidity, // remove liquidity in a form of a single pool token
    HandleEth // ETH <> WETH interaction
}

using ActionLib for Action global;

/// @notice Library for dealing with bit masks which describe what set of Actions is available.
library ActionLib {
    /// @notice Returns a bitmask with all possible actions set to True.
    function allActions() internal pure returns (uint256 actionMask) {
        actionMask = type(uint256).max;
    }

    /// @notice Returns whether the given action is set to True in the bitmask.
    function isIncluded(Action action, uint256 actionMask) internal pure returns (bool) {
        return actionMask & mask(action) != 0;
    }

    /// @notice Returns a bitmask with only the given action set to True.
    function mask(Action action) internal pure returns (uint256) {
        return 1 << uint256(action);
    }

    /// @notice Returns a bitmask with only two given actions set to True.
    function mask(Action a, Action b) internal pure returns (uint256) {
        return mask(a) | mask(b);
    }
}

File 5 of 18 : IFastBridge.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// TODO: This should be pulled from the sanguine repo (requires publish and relaxing the ^0.8.20 pragma)
interface IFastBridge {
    struct BridgeTransaction {
        uint32 originChainId;
        uint32 destChainId;
        address originSender; // user (origin)
        address destRecipient; // user (dest)
        address originToken;
        address destToken;
        uint256 originAmount; // amount in on origin bridge less originFeeAmount
        uint256 destAmount;
        uint256 originFeeAmount;
        bool sendChainGas;
        uint256 deadline;
        uint256 nonce;
    }

    struct BridgeProof {
        uint96 timestamp;
        address relayer;
    }

    // ============ Events ============

    event BridgeRequested(bytes32 transactionId, address sender, bytes request);
    event BridgeRelayed(
        bytes32 transactionId,
        address relayer,
        address to,
        address token,
        uint256 amount,
        uint256 chainGasAmount
    );
    event BridgeProofProvided(bytes32 transactionId, address relayer, bytes32 transactionHash);
    event BridgeProofDisputed(bytes32 transactionId, address relayer);
    event BridgeDepositClaimed(bytes32 transactionId, address relayer, address to, address token, uint256 amount);
    event BridgeDepositRefunded(bytes32 transactionId, address to, address token, uint256 amount);

    // ============ Methods ============

    struct BridgeParams {
        uint32 dstChainId;
        address sender;
        address to;
        address originToken;
        address destToken;
        uint256 originAmount; // should include protocol fee (if any)
        uint256 destAmount; // should include relayer fee
        bool sendChainGas;
        uint256 deadline;
    }

    /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer
    /// @param params The parameters required to bridge
    function bridge(BridgeParams memory params) external payable;

    /// @notice Relays destination side of bridge transaction by off-chain relayer
    /// @param request The encoded bridge transaction to relay on destination chain
    function relay(bytes memory request) external payable;

    /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
    /// @param request The encoded bridge transaction to prove on origin chain
    /// @param destTxHash The destination tx hash proving bridge transaction was relayed
    function prove(bytes memory request, bytes32 destTxHash) external;

    /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital
    /// @param request The encoded bridge transaction to claim on origin chain
    /// @param to The recipient address of the funds
    function claim(bytes memory request, address to) external;

    /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid
    /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute
    function dispute(bytes32 transactionId) external;

    /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed
    /// @param request The encoded bridge transaction to refund
    /// @param to The recipient address of the funds
    function refund(bytes memory request, address to) external;

    // ============ Views ============

    /// @notice Decodes bridge request into a bridge transaction
    /// @param request The bridge request to decode
    function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory);

    /// @notice Checks if the dispute period has passed so bridge deposit can be claimed
    /// @param transactionId The transaction id associated with the encoded bridge transaction to check
    /// @param relayer The address of the relayer attempting to claim
    function canClaim(bytes32 transactionId, address relayer) external view returns (bool);
}

File 6 of 18 : IFastBridgeRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {SwapQuery} from "../../router/libs/Structs.sol";

interface IFastBridgeRouter {
    /// @notice Sets the address of the FastBridge contract
    /// @dev This function is only callable by the owner
    /// @param fastBridge_      The address of the FastBridge contract
    function setFastBridge(address fastBridge_) external;

    /// @notice Sets the address of the SwapQuoter contract
    /// @dev This function is only callable by the owner
    /// @param swapQuoter_      The address of the SwapQuoter contract
    function setSwapQuoter(address swapQuoter_) external;

    /// @notice Initiate an RFQ transaction with an optional swap on origin chain,
    /// and an optional gas rebate on destination chain.
    /// @dev Note that method is payable.
    /// If token is ETH_ADDRESS, this method should be invoked with `msg.value = amountIn`.
    /// If token is ERC20, the tokens will be pulled from msg.sender (use `msg.value = 0`).
    /// Make sure to approve this contract for spending `token` beforehand.
    ///
    /// `originQuery` is supposed to be fetched using FastBridgeRouter.getOriginAmountOut().
    /// Alternatively one could use an external adapter for more complex swaps on the origin chain.
    /// `destQuery.rawParams` signals whether the user wants to receive a gas rebate on the destination chain:
    /// - If the first byte of `destQuery.rawParams` is GAS_REBATE_FLAG, the user wants to receive a gas rebate.
    /// - Otherwise, the user does not want to receive a gas rebate.
    ///
    /// Cross-chain RFQ swap will be performed between tokens: `originQuery.tokenOut` and `destQuery.tokenOut`.
    /// Note: both tokens could be ETH_ADDRESS or ERC20.
    /// Full proceeds of the origin swap are considered the bid for the cross-chain swap.
    /// `destQuery.minAmountOut` is considered the ask for the cross-chain swap.
    /// Note: applying slippage to `destQuery.minAmountOut` will result in a worse price for the user,
    /// the full Relayer quote should be used instead.
    /// @param recipient        Address to receive tokens on destination chain
    /// @param chainId          Destination chain id
    /// @param token            Initial token to be pulled from the user
    /// @param amount           Amount of the initial tokens to be pulled from the user
    /// @param originQuery      Origin swap query (see above)
    /// @param destQuery        Destination swap query (see above)
    function bridge(
        address recipient,
        uint256 chainId,
        address token,
        uint256 amount,
        SwapQuery memory originQuery,
        SwapQuery memory destQuery
    ) external payable;

    // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════

    /// @notice Finds the best path between `tokenIn` and every RFQ token from the given list,
    /// treating the swap as "origin swap", without putting any restrictions on the swap.
    /// @dev Check (query.minAmountOut != 0): this is true only if the swap is possible.
    /// The returned queries with minAmountOut != 0 could be used as `originQuery` with FastBridgeRouter.
    /// Note: it is possible to form a SwapQuery off-chain using alternative SwapAdapter for the origin swap.
    /// @param tokenIn          Initial token that user wants to bridge/swap
    /// @param rfqTokens        List of RFQ tokens
    /// @param amountIn         Amount of tokens user wants to bridge/swap
    /// @return originQueries   List of structs that could be used as `originQuery` in FastBridgeRouter.
    ///                         minAmountOut and deadline fields will need to be adjusted based on the user settings.
    function getOriginAmountOut(
        address tokenIn,
        address[] memory rfqTokens,
        uint256 amountIn
    ) external view returns (SwapQuery[] memory originQueries);

    /// @notice Magic value that indicates that the user wants to receive gas rebate on the destination chain.
    /// This is the answer to the ultimate question of life, the universe, and everything.
    function GAS_REBATE_FLAG() external view returns (bytes1);

    /// @notice Address of the FastBridge contract, used to initiate cross-chain RFQ swaps.
    function fastBridge() external view returns (address);

    /// @notice Address of the SwapQuoter contract, used to fetch quotes for the origin swap.
    function swapQuoter() external view returns (address);
}

File 7 of 18 : ISwapQuoter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {LimitedToken, SwapQuery} from "../../router/libs/Structs.sol";

interface ISwapQuoter {
    function getAmountOut(
        LimitedToken memory tokenIn,
        address tokenOut,
        uint256 amountIn
    ) external view returns (SwapQuery memory query);
}

File 8 of 18 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../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.
 *
 * By default, the owner account will be the one that deploys the contract. 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;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing 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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _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 18 : DefaultAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {IDefaultPool, IDefaultExtendedPool} from "../interfaces/IDefaultExtendedPool.sol";
import {IRouterAdapter} from "../interfaces/IRouterAdapter.sol";
import {IWETH9} from "../interfaces/IWETH9.sol";
import {MsgValueIncorrect, PoolNotFound, TokenAddressMismatch, TokensIdentical} from "../libs/Errors.sol";
import {Action, DefaultParams} from "../libs/Structs.sol";
import {UniversalTokenLib} from "../libs/UniversalToken.sol";

import {SafeERC20, IERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol";

contract DefaultAdapter is IRouterAdapter {
    using SafeERC20 for IERC20;
    using UniversalTokenLib for address;

    /// @notice Enable this contract to receive Ether when withdrawing from WETH.
    /// @dev Consider implementing rescue functions to withdraw Ether from this contract.
    receive() external payable {}

    /// @inheritdoc IRouterAdapter
    function adapterSwap(
        address recipient,
        address tokenIn,
        uint256 amountIn,
        address tokenOut,
        bytes memory rawParams
    ) external payable returns (uint256 amountOut) {
        return _adapterSwap(recipient, tokenIn, amountIn, tokenOut, rawParams);
    }

    /// @dev Internal logic for doing a tokenIn -> tokenOut swap.
    /// Note: `tokenIn` is assumed to have already been transferred to this contract.
    function _adapterSwap(
        address recipient,
        address tokenIn,
        uint256 amountIn,
        address tokenOut,
        bytes memory rawParams
    ) internal virtual returns (uint256 amountOut) {
        // We define a few phases for the whole Adapter's swap process.
        // (?) means the phase is optional.
        // (!) means the phase is mandatory.

        // PHASE 0(!): CHECK ALL THE PARAMS
        DefaultParams memory params = _checkParams(tokenIn, tokenOut, rawParams);

        // PHASE 1(?): WRAP RECEIVED ETH INTO WETH
        tokenIn = _wrapReceivedETH(tokenIn, amountIn, tokenOut, params);
        // After PHASE 1 this contract has `amountIn` worth of `tokenIn`, tokenIn != ETH_ADDRESS

        // PHASE 2(?): PREPARE TO UNWRAP SWAPPED WETH
        address tokenSwapTo = _deriveTokenSwapTo(tokenIn, tokenOut, params);
        // We need to perform tokenIn -> tokenSwapTo action in PHASE 3.
        // if tokenOut == ETH_ADDRESS, we need to unwrap WETH in PHASE 4.
        // Recipient will receive `tokenOut` in PHASE 5.

        // PHASE 3(?): PERFORM A REQUESTED SWAP
        amountOut = _performPoolAction(tokenIn, amountIn, tokenSwapTo, params);
        // After PHASE 3 this contract has `amountOut` worth of `tokenSwapTo`, tokenSwapTo != ETH_ADDRESS

        // PHASE 4(?): UNWRAP SWAPPED WETH
        // Check if the final token is native ETH
        if (tokenOut == UniversalTokenLib.ETH_ADDRESS) {
            // PHASE 2: WETH address was stored as `tokenSwapTo`
            _unwrapETH(tokenSwapTo, amountOut);
        }

        // PHASE 5(!): TRANSFER SWAPPED TOKENS TO RECIPIENT
        // Note: this will transfer native ETH, if tokenOut == ETH_ADDRESS
        // Note: this is a no-op if recipient == address(this)
        tokenOut.universalTransfer(recipient, amountOut);
    }

    /// @dev Checks the params and decodes them into a struct.
    function _checkParams(
        address tokenIn,
        address tokenOut,
        bytes memory rawParams
    ) internal pure returns (DefaultParams memory params) {
        if (tokenIn == tokenOut) revert TokensIdentical();
        // Decode params for swapping via a Default pool
        params = abi.decode(rawParams, (DefaultParams));
        // Swap pool should exist, if action other than HandleEth was requested
        if (params.pool == address(0) && params.action != Action.HandleEth) revert PoolNotFound();
    }

    /// @dev Wraps native ETH into WETH, if requested.
    /// Returns the address of the token this contract ends up with.
    function _wrapReceivedETH(
        address tokenIn,
        uint256 amountIn,
        address tokenOut,
        DefaultParams memory params
    ) internal returns (address wrappedTokenIn) {
        // tokenIn was already transferred to this contract, check if we start from native ETH
        if (tokenIn == UniversalTokenLib.ETH_ADDRESS) {
            // Determine WETH address: this is either tokenOut (if no swap is needed),
            // or a pool token with index `tokenIndexFrom` (if swap is needed).
            wrappedTokenIn = _deriveWethAddress({token: tokenOut, params: params, isTokenFromWeth: true});
            // Wrap ETH into WETH and leave it in this contract
            _wrapETH(wrappedTokenIn, amountIn);
        } else {
            wrappedTokenIn = tokenIn;
            // For ERC20 tokens msg.value should be zero
            if (msg.value != 0) revert MsgValueIncorrect();
        }
    }

    /// @dev Derives the address of token to be received after an action defined in `params`.
    function _deriveTokenSwapTo(
        address tokenIn,
        address tokenOut,
        DefaultParams memory params
    ) internal view returns (address tokenSwapTo) {
        // Check if swap to native ETH was requested
        if (tokenOut == UniversalTokenLib.ETH_ADDRESS) {
            // Determine WETH address: this is either tokenIn (if no swap is needed),
            // or a pool token with index `tokenIndexTo` (if swap is needed).
            tokenSwapTo = _deriveWethAddress({token: tokenIn, params: params, isTokenFromWeth: false});
        } else {
            tokenSwapTo = tokenOut;
        }
    }

    /// @dev Performs an action defined in `params` and returns the amount of `tokenSwapTo` received.
    function _performPoolAction(
        address tokenIn,
        uint256 amountIn,
        address tokenSwapTo,
        DefaultParams memory params
    ) internal returns (uint256 amountOut) {
        // Determine if we need to perform a swap
        if (params.action == Action.HandleEth) {
            // If no swap is required, amountOut doesn't change
            amountOut = amountIn;
        } else {
            // Record balance before the swap
            amountOut = IERC20(tokenSwapTo).balanceOf(address(this));
            // Approve the pool for spending exactly `amountIn` of `tokenIn`
            IERC20(tokenIn).safeIncreaseAllowance(params.pool, amountIn);
            if (params.action == Action.Swap) {
                _swap(params.pool, params, amountIn, tokenSwapTo);
            } else if (params.action == Action.AddLiquidity) {
                _addLiquidity(params.pool, params, amountIn, tokenSwapTo);
            } else {
                // The only remaining action is RemoveLiquidity
                _removeLiquidity(params.pool, params, amountIn, tokenSwapTo);
            }
            // Use the difference between the balance after the swap and the recorded balance as `amountOut`
            amountOut = IERC20(tokenSwapTo).balanceOf(address(this)) - amountOut;
        }
    }

    // ═══════════════════════════════════════ INTERNAL LOGIC: SWAP ACTIONS ════════════════════════════════════════════

    /// @dev Performs a swap through the given pool.
    /// Note: The pool should be already approved for spending `tokenIn`.
    function _swap(
        address pool,
        DefaultParams memory params,
        uint256 amountIn,
        address tokenOut
    ) internal {
        // tokenOut should match the "swap to" token
        if (IDefaultPool(pool).getToken(params.tokenIndexTo) != tokenOut) revert TokenAddressMismatch();
        // amountOut and deadline are not checked in RouterAdapter
        IDefaultPool(pool).swap({
            tokenIndexFrom: params.tokenIndexFrom,
            tokenIndexTo: params.tokenIndexTo,
            dx: amountIn,
            minDy: 0,
            deadline: type(uint256).max
        });
    }

    /// @dev Adds liquidity in a form of a single token to the given pool.
    /// Note: The pool should be already approved for spending `tokenIn`.
    function _addLiquidity(
        address pool,
        DefaultParams memory params,
        uint256 amountIn,
        address tokenOut
    ) internal {
        uint256 numTokens = _getPoolNumTokens(pool);
        address lpToken = _getPoolLPToken(pool);
        // tokenOut should match the LP token
        if (lpToken != tokenOut) revert TokenAddressMismatch();
        uint256[] memory amounts = new uint256[](numTokens);
        amounts[params.tokenIndexFrom] = amountIn;
        // amountOut and deadline are not checked in RouterAdapter
        IDefaultExtendedPool(pool).addLiquidity({amounts: amounts, minToMint: 0, deadline: type(uint256).max});
    }

    /// @dev Removes liquidity in a form of a single token from the given pool.
    /// Note: The pool should be already approved for spending `tokenIn`.
    function _removeLiquidity(
        address pool,
        DefaultParams memory params,
        uint256 amountIn,
        address tokenOut
    ) internal {
        // tokenOut should match the "swap to" token
        if (IDefaultPool(pool).getToken(params.tokenIndexTo) != tokenOut) revert TokenAddressMismatch();
        // amountOut and deadline are not checked in RouterAdapter
        IDefaultExtendedPool(pool).removeLiquidityOneToken({
            tokenAmount: amountIn,
            tokenIndex: params.tokenIndexTo,
            minAmount: 0,
            deadline: type(uint256).max
        });
    }

    // ═════════════════════════════════════════ INTERNAL LOGIC: POOL LENS ═════════════════════════════════════════════

    /// @dev Returns the LP token address of the given pool.
    function _getPoolLPToken(address pool) internal view returns (address lpToken) {
        (, , , , , , lpToken) = IDefaultExtendedPool(pool).swapStorage();
    }

    /// @dev Returns the number of tokens in the given pool.
    function _getPoolNumTokens(address pool) internal view returns (uint256 numTokens) {
        // Iterate over all tokens in the pool until the end is reached
        for (uint8 index = 0; ; ++index) {
            try IDefaultPool(pool).getToken(index) returns (address) {} catch {
                // End of pool reached
                numTokens = index;
                break;
            }
        }
    }

    /// @dev Returns the tokens in the given pool.
    function _getPoolTokens(address pool) internal view returns (address[] memory tokens) {
        uint256 numTokens = _getPoolNumTokens(pool);
        tokens = new address[](numTokens);
        for (uint8 i = 0; i < numTokens; ++i) {
            // This will not revert because we already know the number of tokens in the pool
            tokens[i] = IDefaultPool(pool).getToken(i);
        }
    }

    /// @dev Returns the quote for a swap through the given pool.
    /// Note: will return 0 on invalid swaps.
    function _getPoolSwapQuote(
        address pool,
        uint8 tokenIndexFrom,
        uint8 tokenIndexTo,
        uint256 amountIn
    ) internal view returns (uint256 amountOut) {
        try IDefaultPool(pool).calculateSwap(tokenIndexFrom, tokenIndexTo, amountIn) returns (uint256 dy) {
            amountOut = dy;
        } catch {
            // Return 0 instead of reverting
            amountOut = 0;
        }
    }

    // ════════════════════════════════════════ INTERNAL LOGIC: ETH <> WETH ════════════════════════════════════════════

    /// @dev Wraps ETH into WETH.
    function _wrapETH(address weth, uint256 amount) internal {
        if (amount != msg.value) revert MsgValueIncorrect();
        // Deposit in order to have WETH in this contract
        IWETH9(weth).deposit{value: amount}();
    }

    /// @dev Unwraps WETH into ETH.
    function _unwrapETH(address weth, uint256 amount) internal {
        // Withdraw ETH to this contract
        IWETH9(weth).withdraw(amount);
    }

    /// @dev Derives WETH address from swap parameters.
    function _deriveWethAddress(
        address token,
        DefaultParams memory params,
        bool isTokenFromWeth
    ) internal view returns (address weth) {
        if (params.action == Action.HandleEth) {
            // If we only need to wrap/unwrap ETH, WETH address should be specified as the other token
            weth = token;
        } else {
            // Otherwise, we need to get WETH address from the liquidity pool
            weth = address(
                IDefaultPool(params.pool).getToken(isTokenFromWeth ? params.tokenIndexFrom : params.tokenIndexTo)
            );
        }
    }
}

File 10 of 18 : IRouterAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IRouterAdapter {
    /// @notice Performs a tokenIn -> tokenOut swap, according to the provided params.
    /// If tokenIn is ETH_ADDRESS, this method should be invoked with `msg.value = amountIn`.
    /// If tokenIn is ERC20, the tokens should be already transferred to this contract (using `msg.value = 0`).
    /// If tokenOut is ETH_ADDRESS, native ETH will be sent to the recipient (be aware of potential reentrancy).
    /// If tokenOut is ERC20, the tokens will be transferred to the recipient.
    /// @dev Contracts implementing {IRouterAdapter} interface are required to enforce the above restrictions.
    /// On top of that, they must ensure that exactly `amountOut` worth of `tokenOut` is transferred to the recipient.
    /// Swap deadline and slippage is checked outside of this contract.
    /// @param recipient    Address to receive the swapped token
    /// @param tokenIn      Token to sell (use ETH_ADDRESS to start from native ETH)
    /// @param amountIn     Amount of tokens to sell
    /// @param tokenOut     Token to buy (use ETH_ADDRESS to end with native ETH)
    /// @param rawParams    Additional swap parameters
    /// @return amountOut   Amount of bought tokens
    function adapterSwap(
        address recipient,
        address tokenIn,
        uint256 amountIn,
        address tokenOut,
        bytes calldata rawParams
    ) external payable returns (uint256 amountOut);
}

File 11 of 18 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

error DeadlineExceeded();
error InsufficientOutputAmount();

error MsgValueIncorrect();
error PoolNotFound();
error TokenAddressMismatch();
error TokenNotContract();
error TokenNotETH();
error TokensIdentical();

File 12 of 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 13 of 18 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @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;
    }
}

File 14 of 18 : IDefaultExtendedPool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

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

interface IDefaultExtendedPool is IDefaultPool {
    function addLiquidity(
        uint256[] calldata amounts,
        uint256 minToMint,
        uint256 deadline
    ) external returns (uint256);

    function removeLiquidityOneToken(
        uint256 tokenAmount,
        uint8 tokenIndex,
        uint256 minAmount,
        uint256 deadline
    ) external returns (uint256);

    // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════

    function calculateRemoveLiquidity(uint256 amount) external view returns (uint256[] memory);

    function calculateRemoveLiquidityOneToken(uint256 tokenAmount, uint8 tokenIndex)
        external
        view
        returns (uint256 availableTokenAmount);

    function getAPrecise() external view returns (uint256);

    function getTokenBalance(uint8 index) external view returns (uint256);

    function swapStorage()
        external
        view
        returns (
            uint256 initialA,
            uint256 futureA,
            uint256 initialATime,
            uint256 futureATime,
            uint256 swapFee,
            uint256 adminFee,
            address lpToken
        );
}

File 15 of 18 : IWETH9.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IWETH9 {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

File 16 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);

    /**
     * @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);
}

File 17 of 18 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 18 of 18 : IDefaultPool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IDefaultPool {
    function swap(
        uint8 tokenIndexFrom,
        uint8 tokenIndexTo,
        uint256 dx,
        uint256 minDy,
        uint256 deadline
    ) external returns (uint256 amountOut);

    function calculateSwap(
        uint8 tokenIndexFrom,
        uint8 tokenIndexTo,
        uint256 dx
    ) external view returns (uint256 amountOut);

    function getToken(uint8 index) external view returns (address token);
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "@boringcrypto/=node_modules/@boringcrypto/",
    "@ensdomains/=node_modules/@ensdomains/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat-deploy/=node_modules/hardhat-deploy/",
    "hardhat/=node_modules/hardhat/",
    "sol-explore/=node_modules/sol-explore/",
    "solmate/=lib/solmate/src/",
    "synthetix/=node_modules/synthetix/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"PoolNotFound","type":"error"},{"inputs":[],"name":"TokenAddressMismatch","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TokenNotETH","type":"error"},{"inputs":[],"name":"TokensIdentical","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFastBridge","type":"address"}],"name":"FastBridgeSet","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":false,"internalType":"address","name":"newSwapQuoter","type":"address"}],"name":"SwapQuoterSet","type":"event"},{"inputs":[],"name":"GAS_REBATE_FLAG","outputs":[{"internalType":"bytes1","name":"","type":"bytes1"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"rawParams","type":"bytes"}],"name":"adapterSwap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"address","name":"routerAdapter","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"rawParams","type":"bytes"}],"internalType":"struct SwapQuery","name":"originQuery","type":"tuple"},{"components":[{"internalType":"address","name":"routerAdapter","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"rawParams","type":"bytes"}],"internalType":"struct SwapQuery","name":"destQuery","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fastBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address[]","name":"rfqTokens","type":"address[]"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"getOriginAmountOut","outputs":[{"components":[{"internalType":"address","name":"routerAdapter","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"rawParams","type":"bytes"}],"internalType":"struct SwapQuery[]","name":"originQueries","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fastBridge_","type":"address"}],"name":"setFastBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"swapQuoter_","type":"address"}],"name":"setSwapQuoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapQuoter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b506040516200264138038062002641833981016040819052620000349162000176565b6200003f3362000051565b6200004a81620000a1565b50620001a8565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b03163314620001015760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620001685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620000f8565b620001738162000051565b50565b6000602082840312156200018957600080fd5b81516001600160a01b0381168114620001a157600080fd5b9392505050565b61248980620001b86000396000f3fe6080604052600436106100a05760003560e01c80638da5cb5b116100645780638da5cb5b1461016157806390491b201461017f57806396d292d0146101ac578063bf03b1ea146101dd578063c2288147146101fd578063f2fde38b1461021057600080fd5b806324a98f11146100ac57806334474c8c146100d2578063715018a61461010a5780637673eb1514610121578063804b3dff1461014157600080fd5b366100a757005b600080fd5b6100bf6100ba366004611c6a565b610230565b6040519081526020015b60405180910390f35b3480156100de57600080fd5b506002546100f2906001600160a01b031681565b6040516001600160a01b0390911681526020016100c9565b34801561011657600080fd5b5061011f610249565b005b34801561012d57600080fd5b506001546100f2906001600160a01b031681565b34801561014d57600080fd5b5061011f61015c366004611ce9565b610288565b34801561016d57600080fd5b506000546001600160a01b03166100f2565b34801561018b57600080fd5b5061019f61019a366004611d06565b610307565b6040516100c99190611e25565b3480156101b857600080fd5b506101c4601560f91b81565b6040516001600160f81b031990911681526020016100c9565b3480156101e957600080fd5b5061011f6101f8366004611ce9565b610513565b61011f61020b366004611f4a565b61058b565b34801561021c57600080fd5b5061011f61022b366004611ce9565b610700565b600061023f868686868661079b565b9695505050505050565b6000546001600160a01b0316331461027c5760405162461bcd60e51b815260040161027390611fe5565b60405180910390fd5b6102866000610824565b565b6000546001600160a01b031633146102b25760405162461bcd60e51b815260040161027390611fe5565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f6629f03aaaa02addcc840bd2d3deb4213bcc44a19f3e6601beb3bfcea9528d51906020015b60405180910390a150565b81516060908067ffffffffffffffff81111561032557610325611b7c565b60405190808252806020026020018201604052801561039a57816020015b6103876040518060a0016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b8152602001906001900390816103435790505b50915060005b8181101561050a57600254604080518082019091526001600160a01b039091169063e6b0000990806000198152602001896001600160a01b03168152508784815181106103ef576103ef61201a565b6020908102919091018101516040516001600160e01b031960e086901b1681528351600482015292909101516001600160a01b03908116602484015216604482015260648101879052608401600060405180830381865afa158015610458573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104809190810190612030565b8382815181106104925761049261201a565b60200260200101819052506104c98382815181106104b2576104b261201a565b6020026020010151516001600160a01b0316151590565b156104fa57308382815181106104e1576104e161201a565b60209081029190910101516001600160a01b0390911690525b6105038161212a565b90506103a0565b50509392505050565b6000546001600160a01b0316331461053d5760405162461bcd60e51b815260040161027390611fe5565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f214d83ceb705cb04d7ef7d2fc0dc6e40a0379fff652234e5d1b302ecac39bc53906020016102fc565b81516001600160a01b0316156105b1576105a730858585610874565b90945092506105bf565b6105bc3085856109bf565b92505b60006040518061012001604052808763ffffffff168152602001336001600160a01b03168152602001886001600160a01b03168152602001866001600160a01b0316815260200183602001516001600160a01b03168152602001858152602001836040015181526020016106368460800151610b41565b151581526060840151602090910152600154909150610662906001600160a01b03878116911686610b7e565b60006001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461068f576000610691565b845b60015460405163116145a560e21b81529192506001600160a01b03169063458516949083906106c4908690600401612143565b6000604051808303818588803b1580156106dd57600080fd5b505af11580156106f1573d6000803e3d6000fd5b50505050505050505050505050565b6000546001600160a01b0316331461072a5760405162461bcd60e51b815260040161027390611fe5565b6001600160a01b03811661078f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610273565b61079881610824565b50565b6000806107a9868585610c62565b90506107b786868684610d1b565b955060006107c6878684610d88565b90506107d487878385610dc3565b925073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03861601610805576108058184610f51565b6108196001600160a01b0386168985610faf565b505095945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080826060015142111561089c5760405163559895a360e01b815260040160405180910390fd5b82516108a99086866109bf565b602084015184519195509250306001600160a01b038216036108dd576108d687878786886080015161079b565b9150610990565b6108f06001600160a01b0384168861109b565b9150806001600160a01b03166324a98f1134898989888a608001516040518763ffffffff1660e01b815260040161092b9594939291906121ee565b60206040518083038185885af1158015610949573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061096e9190612229565b50816109836001600160a01b0385168961109b565b61098d9190612242565b91505b83604001518210156109b5576040516342301c2360e01b815260040160405180910390fd5b5094509492505050565b600034600003610ada576109db836001600160a01b031661113d565b6040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190612229565b9050610a5c6001600160a01b0384163386856111a6565b6040516370a0823160e01b81526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac99190612229565b610ad39190612242565b9050610b3a565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610b1757604051632eac7efb60e01b815260040160405180910390fd5b348214610b37576040516381de0bf360e01b815260040160405180910390fd5b50345b9392505050565b6000808251118015610b7857508151601560f91b908390600090610b6757610b6761201a565b01602001516001600160f81b031916145b92915050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ba857505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c9190612229565b9050818110610c2b5750505050565b8015610c4657610c466001600160a01b038516846000611211565b610c5c6001600160a01b03851684600019611211565b50505050565b604080516080810182526000808252602082018190529181018290526060810191909152826001600160a01b0316846001600160a01b031603610cb857604051630b839a1f60e01b815260040160405180910390fd5b81806020019051810190610ccc919061226b565b60208101519091506001600160a01b0316158015610cfd5750600381516003811115610cfa57610cfa6122f0565b14155b15610b3a576040516301dbb3ff60e61b815260040160405180910390fd5b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03861601610d5f57610d4e83836001611326565b9050610d5a81856113d3565b610d80565b50833415610d80576040516381de0bf360e01b815260040160405180910390fd5b949350505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610dbb57610ad384836000611326565b509092915050565b6000600382516003811115610dda57610dda6122f0565b03610de6575082610d80565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610e2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4e9190612229565b6020830151909150610e6b906001600160a01b038716908661144b565b600082516003811115610e8057610e806122f0565b03610e9a57610e9582602001518386866114fd565b610ed4565b600182516003811115610eaf57610eaf6122f0565b03610ec457610e958260200151838686611636565b610ed4826020015183868661176e565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015610f1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3e9190612229565b610f489190612242565b95945050505050565b604051632e1a7d4d60e01b8152600481018290526001600160a01b03831690632e1a7d4d90602401600060405180830381600087803b158015610f9357600080fd5b505af1158015610fa7573d6000803e3d6000fd5b505050505050565b306001600160a01b03831603610fc457505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611082576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611036576040519150601f19603f3d011682016040523d82523d6000602084013e61103b565b606091505b5050905080610c5c5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610273565b6110966001600160a01b0384168383611855565b505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016110d357506001600160a01b03811631610b78565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015611119573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3a9190612229565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161117b57604051630fea47fd60e31b815260040160405180910390fd5b806001600160a01b03163b60000361079857604051630fea47fd60e31b815260040160405180910390fd5b6040516001600160a01b0380851660248301528316604482015260648101829052610c5c9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611885565b80158061128b5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112899190612229565b155b6112f65760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610273565b6040516001600160a01b03831660248201526044810182905261109690849063095ea7b360e01b906064016111da565b600060038351600381111561133d5761133d6122f0565b03611349575082610b3a565b82602001516001600160a01b03166382b866008361136b578460600151611371565b84604001515b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865afa1580156113af573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d809190612306565b3481146113f3576040516381de0bf360e01b815260040160405180910390fd5b816001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561142e57600080fd5b505af1158015611442573d6000803e3d6000fd5b50505050505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190612229565b6114ca9190612323565b6040516001600160a01b038516602482015260448101829052909150610c5c90859063095ea7b360e01b906064016111da565b606083015160405162415c3360e91b815260ff90911660048201526001600160a01b0382811691908616906382b8660090602401602060405180830381865afa15801561154e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115729190612306565b6001600160a01b03161461159957604051631438b5c960e11b815260040160405180910390fd5b604080840151606085015191516348b4aac360e11b815260ff918216600482015291166024820152604481018390526000606482015260001960848201526001600160a01b0385169063916955869060a4015b6020604051808303816000875af115801561160b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162f9190612229565b5050505050565b600061164185611957565b9050600061164e866119e3565b9050826001600160a01b0316816001600160a01b03161461168257604051631438b5c960e11b815260040160405180910390fd5b60008267ffffffffffffffff81111561169d5761169d611b7c565b6040519080825280602002602001820160405280156116c6578160200160208202803683370190505b5090508481876040015160ff16815181106116e3576116e361201a565b6020908102919091010152604051634d49e87d60e01b81526001600160a01b03881690634d49e87d9061172190849060009060001990600401612336565b6020604051808303816000875af1158015611740573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117649190612229565b5050505050505050565b606083015160405162415c3360e91b815260ff90911660048201526001600160a01b0382811691908616906382b8660090602401602060405180830381865afa1580156117bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e39190612306565b6001600160a01b03161461180a57604051631438b5c960e11b815260040160405180910390fd5b60608301516040516301f1d0ab60e51b81526004810184905260ff90911660248201526000604482015260001960648201526001600160a01b03851690633e3a1560906084016115ec565b6040516001600160a01b03831660248201526044810182905261109690849063a9059cbb60e01b906064016111da565b60006118da826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611a539092919063ffffffff16565b80519091501561109657808060200190518101906118f89190612383565b6110965760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610273565b6000805b60405162415c3360e91b815260ff821660048201526001600160a01b038416906382b8660090602401602060405180830381865afa9250505080156119bd575060408051601f3d908101601f191682019092526119ba91810190612306565b60015b6119cc578060ff1691506119dd565b506119d6816123a5565b905061195b565b50919050565b6000816001600160a01b0316635fd65f0f6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611a23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4791906123c4565b98975050505050505050565b6060610d808484600085856001600160a01b0385163b611ab55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610273565b600080866001600160a01b03168587604051611ad19190612424565b60006040518083038185875af1925050503d8060008114611b0e576040519150601f19603f3d011682016040523d82523d6000602084013e611b13565b606091505b5091509150611b23828286611b2e565b979650505050505050565b60608315611b3d575081610b3a565b825115611b4d5782518084602001fd5b8160405162461bcd60e51b81526004016102739190612440565b6001600160a01b038116811461079857600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715611bb557611bb5611b7c565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611be457611be4611b7c565b604052919050565b600067ffffffffffffffff821115611c0657611c06611b7c565b50601f01601f191660200190565b600082601f830112611c2557600080fd5b8135611c38611c3382611bec565b611bbb565b818152846020838601011115611c4d57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611c8257600080fd5b8535611c8d81611b67565b94506020860135611c9d81611b67565b9350604086013592506060860135611cb481611b67565b9150608086013567ffffffffffffffff811115611cd057600080fd5b611cdc88828901611c14565b9150509295509295909350565b600060208284031215611cfb57600080fd5b8135610b3a81611b67565b600080600060608486031215611d1b57600080fd5b8335611d2681611b67565b925060208481013567ffffffffffffffff80821115611d4457600080fd5b818701915087601f830112611d5857600080fd5b813581811115611d6a57611d6a611b7c565b8060051b9150611d7b848301611bbb565b818152918301840191848101908a841115611d9557600080fd5b938501935b83851015611dbf5784359250611daf83611b67565b8282529385019390850190611d9a565b979a979950505050604095909501359450505050565b60005b83811015611df0578181015183820152602001611dd8565b50506000910152565b60008151808452611e11816020860160208601611dd5565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015611eb857888303603f19018552815180516001600160a01b03908116855288820151168885015286810151878501526060808201519085015260809081015160a091850182905290611ea481860183611df9565b968901969450505090860190600101611e4c565b509098975050505050505050565b600060a08284031215611ed857600080fd5b611ee0611b92565b90508135611eed81611b67565b81526020820135611efd81611b67565b806020830152506040820135604082015260608201356060820152608082013567ffffffffffffffff811115611f3257600080fd5b611f3e84828501611c14565b60808301525092915050565b60008060008060008060c08789031215611f6357600080fd5b8635611f6e81611b67565b9550602087013594506040870135611f8581611b67565b935060608701359250608087013567ffffffffffffffff80821115611fa957600080fd5b611fb58a838b01611ec6565b935060a0890135915080821115611fcb57600080fd5b50611fd889828a01611ec6565b9150509295509295509295565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561204357600080fd5b825167ffffffffffffffff8082111561205b57600080fd5b9084019060a0828703121561206f57600080fd5b612077611b92565b825161208281611b67565b81528284015161209181611b67565b80858301525060408301516040820152606083015160608201526080830151828111156120bd57600080fd5b80840193505086601f8401126120d257600080fd5b825191506120e2611c3383611bec565b82815287858486010111156120f657600080fd5b61210583868301878701611dd5565b60808201529695505050505050565b634e487b7160e01b600052601160045260246000fd5b60006001820161213c5761213c612114565b5060010190565b815163ffffffff1681526020808301516001600160a01b031690820152604080830151610120830191612180908401826001600160a01b03169052565b50606083015161219b60608401826001600160a01b03169052565b5060808301516121b660808401826001600160a01b03169052565b5060a083015160a083015260c083015160c083015260e08301516121de60e084018215159052565b5061010092830151919092015290565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090611b2390830184611df9565b60006020828403121561223b57600080fd5b5051919050565b81810381811115610b7857610b78612114565b805160ff8116811461226657600080fd5b919050565b60006080828403121561227d57600080fd5b6040516080810181811067ffffffffffffffff821117156122a0576122a0611b7c565b6040528251600481106122b257600080fd5b815260208301516122c281611b67565b60208201526122d360408401612255565b60408201526122e460608401612255565b60608201529392505050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561231857600080fd5b8151610b3a81611b67565b80820180821115610b7857610b78612114565b606080825284519082018190526000906020906080840190828801845b8281101561236f57815184529284019290840190600101612353565b505050908301949094525060400152919050565b60006020828403121561239557600080fd5b81518015158114610b3a57600080fd5b600060ff821660ff81036123bb576123bb612114565b60010192915050565b600080600080600080600060e0888a0312156123df57600080fd5b875196506020880151955060408801519450606088015193506080880151925060a0880151915060c088015161241481611b67565b8091505092959891949750929550565b60008251612436818460208701611dd5565b9190910192915050565b602081526000610b3a6020830184611df956fea2646970667358221220af10d1b0353aa1b3b19ea56d105f9744c1a60029dc0a7a2abce7b8995fd9349664736f6c634300081100330000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3

Deployed Bytecode

0x6080604052600436106100a05760003560e01c80638da5cb5b116100645780638da5cb5b1461016157806390491b201461017f57806396d292d0146101ac578063bf03b1ea146101dd578063c2288147146101fd578063f2fde38b1461021057600080fd5b806324a98f11146100ac57806334474c8c146100d2578063715018a61461010a5780637673eb1514610121578063804b3dff1461014157600080fd5b366100a757005b600080fd5b6100bf6100ba366004611c6a565b610230565b6040519081526020015b60405180910390f35b3480156100de57600080fd5b506002546100f2906001600160a01b031681565b6040516001600160a01b0390911681526020016100c9565b34801561011657600080fd5b5061011f610249565b005b34801561012d57600080fd5b506001546100f2906001600160a01b031681565b34801561014d57600080fd5b5061011f61015c366004611ce9565b610288565b34801561016d57600080fd5b506000546001600160a01b03166100f2565b34801561018b57600080fd5b5061019f61019a366004611d06565b610307565b6040516100c99190611e25565b3480156101b857600080fd5b506101c4601560f91b81565b6040516001600160f81b031990911681526020016100c9565b3480156101e957600080fd5b5061011f6101f8366004611ce9565b610513565b61011f61020b366004611f4a565b61058b565b34801561021c57600080fd5b5061011f61022b366004611ce9565b610700565b600061023f868686868661079b565b9695505050505050565b6000546001600160a01b0316331461027c5760405162461bcd60e51b815260040161027390611fe5565b60405180910390fd5b6102866000610824565b565b6000546001600160a01b031633146102b25760405162461bcd60e51b815260040161027390611fe5565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f6629f03aaaa02addcc840bd2d3deb4213bcc44a19f3e6601beb3bfcea9528d51906020015b60405180910390a150565b81516060908067ffffffffffffffff81111561032557610325611b7c565b60405190808252806020026020018201604052801561039a57816020015b6103876040518060a0016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b8152602001906001900390816103435790505b50915060005b8181101561050a57600254604080518082019091526001600160a01b039091169063e6b0000990806000198152602001896001600160a01b03168152508784815181106103ef576103ef61201a565b6020908102919091018101516040516001600160e01b031960e086901b1681528351600482015292909101516001600160a01b03908116602484015216604482015260648101879052608401600060405180830381865afa158015610458573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104809190810190612030565b8382815181106104925761049261201a565b60200260200101819052506104c98382815181106104b2576104b261201a565b6020026020010151516001600160a01b0316151590565b156104fa57308382815181106104e1576104e161201a565b60209081029190910101516001600160a01b0390911690525b6105038161212a565b90506103a0565b50509392505050565b6000546001600160a01b0316331461053d5760405162461bcd60e51b815260040161027390611fe5565b600180546001600160a01b0319166001600160a01b0383169081179091556040519081527f214d83ceb705cb04d7ef7d2fc0dc6e40a0379fff652234e5d1b302ecac39bc53906020016102fc565b81516001600160a01b0316156105b1576105a730858585610874565b90945092506105bf565b6105bc3085856109bf565b92505b60006040518061012001604052808763ffffffff168152602001336001600160a01b03168152602001886001600160a01b03168152602001866001600160a01b0316815260200183602001516001600160a01b03168152602001858152602001836040015181526020016106368460800151610b41565b151581526060840151602090910152600154909150610662906001600160a01b03878116911686610b7e565b60006001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461068f576000610691565b845b60015460405163116145a560e21b81529192506001600160a01b03169063458516949083906106c4908690600401612143565b6000604051808303818588803b1580156106dd57600080fd5b505af11580156106f1573d6000803e3d6000fd5b50505050505050505050505050565b6000546001600160a01b0316331461072a5760405162461bcd60e51b815260040161027390611fe5565b6001600160a01b03811661078f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610273565b61079881610824565b50565b6000806107a9868585610c62565b90506107b786868684610d1b565b955060006107c6878684610d88565b90506107d487878385610dc3565b925073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03861601610805576108058184610f51565b6108196001600160a01b0386168985610faf565b505095945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080826060015142111561089c5760405163559895a360e01b815260040160405180910390fd5b82516108a99086866109bf565b602084015184519195509250306001600160a01b038216036108dd576108d687878786886080015161079b565b9150610990565b6108f06001600160a01b0384168861109b565b9150806001600160a01b03166324a98f1134898989888a608001516040518763ffffffff1660e01b815260040161092b9594939291906121ee565b60206040518083038185885af1158015610949573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061096e9190612229565b50816109836001600160a01b0385168961109b565b61098d9190612242565b91505b83604001518210156109b5576040516342301c2360e01b815260040160405180910390fd5b5094509492505050565b600034600003610ada576109db836001600160a01b031661113d565b6040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015610a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a459190612229565b9050610a5c6001600160a01b0384163386856111a6565b6040516370a0823160e01b81526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015610aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac99190612229565b610ad39190612242565b9050610b3a565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610b1757604051632eac7efb60e01b815260040160405180910390fd5b348214610b37576040516381de0bf360e01b815260040160405180910390fd5b50345b9392505050565b6000808251118015610b7857508151601560f91b908390600090610b6757610b6761201a565b01602001516001600160f81b031916145b92915050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610ba857505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015610bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1c9190612229565b9050818110610c2b5750505050565b8015610c4657610c466001600160a01b038516846000611211565b610c5c6001600160a01b03851684600019611211565b50505050565b604080516080810182526000808252602082018190529181018290526060810191909152826001600160a01b0316846001600160a01b031603610cb857604051630b839a1f60e01b815260040160405180910390fd5b81806020019051810190610ccc919061226b565b60208101519091506001600160a01b0316158015610cfd5750600381516003811115610cfa57610cfa6122f0565b14155b15610b3a576040516301dbb3ff60e61b815260040160405180910390fd5b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03861601610d5f57610d4e83836001611326565b9050610d5a81856113d3565b610d80565b50833415610d80576040516381de0bf360e01b815260040160405180910390fd5b949350505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601610dbb57610ad384836000611326565b509092915050565b6000600382516003811115610dda57610dda6122f0565b03610de6575082610d80565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610e2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4e9190612229565b6020830151909150610e6b906001600160a01b038716908661144b565b600082516003811115610e8057610e806122f0565b03610e9a57610e9582602001518386866114fd565b610ed4565b600182516003811115610eaf57610eaf6122f0565b03610ec457610e958260200151838686611636565b610ed4826020015183868661176e565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015610f1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3e9190612229565b610f489190612242565b95945050505050565b604051632e1a7d4d60e01b8152600481018290526001600160a01b03831690632e1a7d4d90602401600060405180830381600087803b158015610f9357600080fd5b505af1158015610fa7573d6000803e3d6000fd5b505050505050565b306001600160a01b03831603610fc457505050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03841601611082576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611036576040519150601f19603f3d011682016040523d82523d6000602084013e61103b565b606091505b5050905080610c5c5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610273565b6110966001600160a01b0384168383611855565b505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038416016110d357506001600160a01b03811631610b78565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015611119573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3a9190612229565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161117b57604051630fea47fd60e31b815260040160405180910390fd5b806001600160a01b03163b60000361079857604051630fea47fd60e31b815260040160405180910390fd5b6040516001600160a01b0380851660248301528316604482015260648101829052610c5c9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611885565b80158061128b5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611265573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112899190612229565b155b6112f65760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610273565b6040516001600160a01b03831660248201526044810182905261109690849063095ea7b360e01b906064016111da565b600060038351600381111561133d5761133d6122f0565b03611349575082610b3a565b82602001516001600160a01b03166382b866008361136b578460600151611371565b84604001515b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865afa1580156113af573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d809190612306565b3481146113f3576040516381de0bf360e01b815260040160405180910390fd5b816001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561142e57600080fd5b505af1158015611442573d6000803e3d6000fd5b50505050505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801561149c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c09190612229565b6114ca9190612323565b6040516001600160a01b038516602482015260448101829052909150610c5c90859063095ea7b360e01b906064016111da565b606083015160405162415c3360e91b815260ff90911660048201526001600160a01b0382811691908616906382b8660090602401602060405180830381865afa15801561154e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115729190612306565b6001600160a01b03161461159957604051631438b5c960e11b815260040160405180910390fd5b604080840151606085015191516348b4aac360e11b815260ff918216600482015291166024820152604481018390526000606482015260001960848201526001600160a01b0385169063916955869060a4015b6020604051808303816000875af115801561160b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162f9190612229565b5050505050565b600061164185611957565b9050600061164e866119e3565b9050826001600160a01b0316816001600160a01b03161461168257604051631438b5c960e11b815260040160405180910390fd5b60008267ffffffffffffffff81111561169d5761169d611b7c565b6040519080825280602002602001820160405280156116c6578160200160208202803683370190505b5090508481876040015160ff16815181106116e3576116e361201a565b6020908102919091010152604051634d49e87d60e01b81526001600160a01b03881690634d49e87d9061172190849060009060001990600401612336565b6020604051808303816000875af1158015611740573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117649190612229565b5050505050505050565b606083015160405162415c3360e91b815260ff90911660048201526001600160a01b0382811691908616906382b8660090602401602060405180830381865afa1580156117bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e39190612306565b6001600160a01b03161461180a57604051631438b5c960e11b815260040160405180910390fd5b60608301516040516301f1d0ab60e51b81526004810184905260ff90911660248201526000604482015260001960648201526001600160a01b03851690633e3a1560906084016115ec565b6040516001600160a01b03831660248201526044810182905261109690849063a9059cbb60e01b906064016111da565b60006118da826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611a539092919063ffffffff16565b80519091501561109657808060200190518101906118f89190612383565b6110965760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610273565b6000805b60405162415c3360e91b815260ff821660048201526001600160a01b038416906382b8660090602401602060405180830381865afa9250505080156119bd575060408051601f3d908101601f191682019092526119ba91810190612306565b60015b6119cc578060ff1691506119dd565b506119d6816123a5565b905061195b565b50919050565b6000816001600160a01b0316635fd65f0f6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611a23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4791906123c4565b98975050505050505050565b6060610d808484600085856001600160a01b0385163b611ab55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610273565b600080866001600160a01b03168587604051611ad19190612424565b60006040518083038185875af1925050503d8060008114611b0e576040519150601f19603f3d011682016040523d82523d6000602084013e611b13565b606091505b5091509150611b23828286611b2e565b979650505050505050565b60608315611b3d575081610b3a565b825115611b4d5782518084602001fd5b8160405162461bcd60e51b81526004016102739190612440565b6001600160a01b038116811461079857600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715611bb557611bb5611b7c565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611be457611be4611b7c565b604052919050565b600067ffffffffffffffff821115611c0657611c06611b7c565b50601f01601f191660200190565b600082601f830112611c2557600080fd5b8135611c38611c3382611bec565b611bbb565b818152846020838601011115611c4d57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611c8257600080fd5b8535611c8d81611b67565b94506020860135611c9d81611b67565b9350604086013592506060860135611cb481611b67565b9150608086013567ffffffffffffffff811115611cd057600080fd5b611cdc88828901611c14565b9150509295509295909350565b600060208284031215611cfb57600080fd5b8135610b3a81611b67565b600080600060608486031215611d1b57600080fd5b8335611d2681611b67565b925060208481013567ffffffffffffffff80821115611d4457600080fd5b818701915087601f830112611d5857600080fd5b813581811115611d6a57611d6a611b7c565b8060051b9150611d7b848301611bbb565b818152918301840191848101908a841115611d9557600080fd5b938501935b83851015611dbf5784359250611daf83611b67565b8282529385019390850190611d9a565b979a979950505050604095909501359450505050565b60005b83811015611df0578181015183820152602001611dd8565b50506000910152565b60008151808452611e11816020860160208601611dd5565b601f01601f19169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015611eb857888303603f19018552815180516001600160a01b03908116855288820151168885015286810151878501526060808201519085015260809081015160a091850182905290611ea481860183611df9565b968901969450505090860190600101611e4c565b509098975050505050505050565b600060a08284031215611ed857600080fd5b611ee0611b92565b90508135611eed81611b67565b81526020820135611efd81611b67565b806020830152506040820135604082015260608201356060820152608082013567ffffffffffffffff811115611f3257600080fd5b611f3e84828501611c14565b60808301525092915050565b60008060008060008060c08789031215611f6357600080fd5b8635611f6e81611b67565b9550602087013594506040870135611f8581611b67565b935060608701359250608087013567ffffffffffffffff80821115611fa957600080fd5b611fb58a838b01611ec6565b935060a0890135915080821115611fcb57600080fd5b50611fd889828a01611ec6565b9150509295509295509295565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000602080838503121561204357600080fd5b825167ffffffffffffffff8082111561205b57600080fd5b9084019060a0828703121561206f57600080fd5b612077611b92565b825161208281611b67565b81528284015161209181611b67565b80858301525060408301516040820152606083015160608201526080830151828111156120bd57600080fd5b80840193505086601f8401126120d257600080fd5b825191506120e2611c3383611bec565b82815287858486010111156120f657600080fd5b61210583868301878701611dd5565b60808201529695505050505050565b634e487b7160e01b600052601160045260246000fd5b60006001820161213c5761213c612114565b5060010190565b815163ffffffff1681526020808301516001600160a01b031690820152604080830151610120830191612180908401826001600160a01b03169052565b50606083015161219b60608401826001600160a01b03169052565b5060808301516121b660808401826001600160a01b03169052565b5060a083015160a083015260c083015160c083015260e08301516121de60e084018215159052565b5061010092830151919092015290565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a060808201819052600090611b2390830184611df9565b60006020828403121561223b57600080fd5b5051919050565b81810381811115610b7857610b78612114565b805160ff8116811461226657600080fd5b919050565b60006080828403121561227d57600080fd5b6040516080810181811067ffffffffffffffff821117156122a0576122a0611b7c565b6040528251600481106122b257600080fd5b815260208301516122c281611b67565b60208201526122d360408401612255565b60408201526122e460608401612255565b60608201529392505050565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561231857600080fd5b8151610b3a81611b67565b80820180821115610b7857610b78612114565b606080825284519082018190526000906020906080840190828801845b8281101561236f57815184529284019290840190600101612353565b505050908301949094525060400152919050565b60006020828403121561239557600080fd5b81518015158114610b3a57600080fd5b600060ff821660ff81036123bb576123bb612114565b60010192915050565b600080600080600080600060e0888a0312156123df57600080fd5b875196506020880151955060408801519450606088015193506080880151925060a0880151915060c088015161241481611b67565b8091505092959891949750929550565b60008251612436818460208701611dd5565b9190910192915050565b602081526000610b3a6020830184611df956fea2646970667358221220af10d1b0353aa1b3b19ea56d105f9744c1a60029dc0a7a2abce7b8995fd9349664736f6c63430008110033

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

0000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3

-----Decoded View---------------
Arg [0] : owner_ (address): 0x0fea3e5840334Fc758A3DECf14546bFdfBef5cd3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000fea3e5840334fc758a3decf14546bfdfbef5cd3


Block Transaction Difficulty 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
Loading...
Loading
[ 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.