ETH Price: $3,682.94 (+19.61%)
Gas: 11 Gwei

Contract

0x0000000000489d89D2B233D3375C045dfD05745F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Bridge199152552024-05-21 2:19:2325 mins ago1716257963IN
0x00000000...dfD05745F
0.1 ETH0.000794689.85062843
Bridge199152012024-05-21 2:08:3536 mins ago1716257315IN
0x00000000...dfD05745F
0 ETH0.0014682612.0353788
Bridge199151812024-05-21 2:04:3540 mins ago1716257075IN
0x00000000...dfD05745F
0 ETH0.0015152212.42393137
Bridge199150542024-05-21 1:39:111 hr ago1716255551IN
0x00000000...dfD05745F
1 ETH0.000934511.58367379
Bridge199149672024-05-21 1:21:351 hr ago1716254495IN
0x00000000...dfD05745F
2.72 ETH0.0012384215.35103788
Bridge199149652024-05-21 1:21:111 hr ago1716254471IN
0x00000000...dfD05745F
0.5177 ETH0.0012950116.05006381
Bridge199149382024-05-21 1:15:471 hr ago1716254147IN
0x00000000...dfD05745F
1.1 ETH0.0012970416.07758964
Bridge199148652024-05-21 1:00:591 hr ago1716253259IN
0x00000000...dfD05745F
0.16 ETH0.0012109815.01304905
Bridge199148562024-05-21 0:59:111 hr ago1716253151IN
0x00000000...dfD05745F
0.032 ETH0.0012434115.42434757
Bridge199148202024-05-21 0:51:591 hr ago1716252719IN
0x00000000...dfD05745F
0 ETH0.0020462416.77302523
Bridge199148052024-05-21 0:48:591 hr ago1716252539IN
0x00000000...dfD05745F
0 ETH0.0020032916.4225853
Bridge199147222024-05-21 0:31:592 hrs ago1716251519IN
0x00000000...dfD05745F
0.1929 ETH0.0014078817.45147768
Bridge199146722024-05-21 0:21:592 hrs ago1716250919IN
0x00000000...dfD05745F
4.02 ETH0.0014108817.48876831
Bridge199146672024-05-21 0:20:592 hrs ago1716250859IN
0x00000000...dfD05745F
0.10364881 ETH0.0012354215.30927909
Bridge199145982024-05-21 0:06:472 hrs ago1716250007IN
0x00000000...dfD05745F
0 ETH0.0048321614.99087923
Bridge199144312024-05-20 23:33:113 hrs ago1716247991IN
0x00000000...dfD05745F
0 ETH0.0031165125.55358285
Bridge199144092024-05-20 23:28:473 hrs ago1716247727IN
0x00000000...dfD05745F
0.1 ETH0.0015030618.63410565
Bridge199144072024-05-20 23:28:233 hrs ago1716247703IN
0x00000000...dfD05745F
0.447 ETH0.0014521318
Bridge199143992024-05-20 23:26:473 hrs ago1716247607IN
0x00000000...dfD05745F
0.1182562 ETH0.0017517421.71063065
Bridge199143872024-05-20 23:24:113 hrs ago1716247451IN
0x00000000...dfD05745F
0.033 ETH0.0015757319.5437982
Bridge199143662024-05-20 23:19:593 hrs ago1716247199IN
0x00000000...dfD05745F
7 ETH0.0017097221.19302566
Bridge199143482024-05-20 23:16:233 hrs ago1716246983IN
0x00000000...dfD05745F
0 ETH0.0029734224.37794902
Bridge199141152024-05-20 22:29:234 hrs ago1716244163IN
0x00000000...dfD05745F
0.025 ETH0.0028046734.7810154
Bridge199140372024-05-20 22:13:354 hrs ago1716243215IN
0x00000000...dfD05745F
4.74457037 ETH0.002448530.34614266
Bridge199140302024-05-20 22:12:114 hrs ago1716243131IN
0x00000000...dfD05745F
0 ETH0.003439928.1968291
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
199152552024-05-21 2:19:2325 mins ago1716257963
0x00000000...dfD05745F
0.1 ETH
199150542024-05-21 1:39:111 hr ago1716255551
0x00000000...dfD05745F
1 ETH
199149672024-05-21 1:21:351 hr ago1716254495
0x00000000...dfD05745F
2.72 ETH
199149652024-05-21 1:21:111 hr ago1716254471
0x00000000...dfD05745F
0.5177 ETH
199149382024-05-21 1:15:471 hr ago1716254147
0x00000000...dfD05745F
1.1 ETH
199148652024-05-21 1:00:591 hr ago1716253259
0x00000000...dfD05745F
0.16 ETH
199148562024-05-21 0:59:111 hr ago1716253151
0x00000000...dfD05745F
0.032 ETH
199147222024-05-21 0:31:592 hrs ago1716251519
0x00000000...dfD05745F
0.1929 ETH
199146722024-05-21 0:21:592 hrs ago1716250919
0x00000000...dfD05745F
4.02 ETH
199146672024-05-21 0:20:592 hrs ago1716250859
0x00000000...dfD05745F
0.10364881 ETH
199144092024-05-20 23:28:473 hrs ago1716247727
0x00000000...dfD05745F
0.1 ETH
199144072024-05-20 23:28:233 hrs ago1716247703
0x00000000...dfD05745F
0.447 ETH
199143992024-05-20 23:26:473 hrs ago1716247607
0x00000000...dfD05745F
0.1182562 ETH
199143872024-05-20 23:24:113 hrs ago1716247451
0x00000000...dfD05745F
0.033 ETH
199143662024-05-20 23:19:593 hrs ago1716247199
0x00000000...dfD05745F
7 ETH
199141152024-05-20 22:29:234 hrs ago1716244163
0x00000000...dfD05745F
0.025 ETH
199140372024-05-20 22:13:354 hrs ago1716243215
0x00000000...dfD05745F
4.74457037 ETH
199140172024-05-20 22:09:354 hrs ago1716242975
0x00000000...dfD05745F
0.56 ETH
199139812024-05-20 22:02:234 hrs ago1716242543
0x00000000...dfD05745F
0.51 ETH
199138982024-05-20 21:45:474 hrs ago1716241547
0x00000000...dfD05745F
3.5 ETH
199138512024-05-20 21:36:235 hrs ago1716240983
0x00000000...dfD05745F
4.3 ETH
199136892024-05-20 21:03:355 hrs ago1716239015
0x00000000...dfD05745F
1.1 ETH
199134472024-05-20 20:15:116 hrs ago1716236111
0x00000000...dfD05745F
1.86 ETH
199132632024-05-20 19:38:237 hrs ago1716233903
0x00000000...dfD05745F
0.12040592 ETH
199129362024-05-20 18:32:358 hrs ago1716229955
0x00000000...dfD05745F
0.01277179 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 3 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 4 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 5 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 6 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 7 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 8 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 9 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 10 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 11 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 12 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 13 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 14 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 15 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 16 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 17 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 18 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 19 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.