ETH Price: $3,944.59 (-1.41%)

Contract

0x9b2Ed3C2a92ad366eBF90bBceC31BE231320aC26

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

Transaction Hash
Method
Block
From
To
Execute Order1167884162024-02-29 3:00:09284 days ago1709175609IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002098087360.10095069
Execute Order1167580022024-02-28 10:06:21284 days ago1709114781IN
0x9b2Ed3C2...31320aC26
0 ETH0.0012575251520.09932625
Execute Order1166889782024-02-26 19:45:33286 days ago1708976733IN
0x9b2Ed3C2...31320aC26
0 ETH0.0005988540640.00541747
Execute Order1164625302024-02-21 13:57:17291 days ago1708523837IN
0x9b2Ed3C2...31320aC26
0 ETH0.000194136630.00393653
Execute Order1164249502024-02-20 17:04:37292 days ago1708448677IN
0x9b2Ed3C2...31320aC26
0 ETH0.0005489617870.00633481
Execute Order1164248932024-02-20 17:02:43292 days ago1708448563IN
0x9b2Ed3C2...31320aC26
0 ETH0.0006157324080.00620996
Execute Order1164202652024-02-20 14:28:27292 days ago1708439307IN
0x9b2Ed3C2...31320aC26
0 ETH0.000706890880.00628797
Execute Order1164201992024-02-20 14:26:15292 days ago1708439175IN
0x9b2Ed3C2...31320aC26
0 ETH0.0005829828440.00667048
Execute Order1164175692024-02-20 12:58:35292 days ago1708433915IN
0x9b2Ed3C2...31320aC26
0 ETH0.0005643503790.00413536
Execute Order1164174772024-02-20 12:55:31292 days ago1708433731IN
0x9b2Ed3C2...31320aC26
0 ETH0.0004376837910.00406527
Execute Order1164135182024-02-20 10:43:33292 days ago1708425813IN
0x9b2Ed3C2...31320aC26
0 ETH0.0003957371240.00493817
Execute Order1164133462024-02-20 10:37:49292 days ago1708425469IN
0x9b2Ed3C2...31320aC26
0 ETH0.0003225752280.00469264
Execute Order1164130892024-02-20 10:29:15292 days ago1708424955IN
0x9b2Ed3C2...31320aC26
0 ETH0.0004155502170.00438296
Execute Order1163725282024-02-19 11:57:13293 days ago1708343833IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002846089340.00600898
Execute Order1163700802024-02-19 10:35:37293 days ago1708338937IN
0x9b2Ed3C2...31320aC26
0.00005 ETH0.0002773091670.00488055
Execute Order1163685382024-02-19 9:44:13293 days ago1708335853IN
0x9b2Ed3C2...31320aC26
0.037 ETH0.0002933662760.00506842
Execute Order1163679192024-02-19 9:23:35293 days ago1708334615IN
0x9b2Ed3C2...31320aC26
0.0005 ETH0.0005390005950.00493146
Execute Order1163115372024-02-18 2:04:11295 days ago1708221851IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002391805040.00504543
Execute Order1163101312024-02-18 1:17:19295 days ago1708219039IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002587287790.00472608
Execute Order1162273782024-02-16 3:18:53296 days ago1708053533IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002071128440.00422893
Execute Order1160683832024-02-12 10:59:03300 days ago1707735543IN
0x9b2Ed3C2...31320aC26
0.00043 ETH0.0002356740230.09828947
Execute Order1156949422024-02-03 19:31:01309 days ago1706988661IN
0x9b2Ed3C2...31320aC26
0 ETH0.000166470020.08309603
Execute Order1156268622024-02-02 5:41:41310 days ago1706852501IN
0x9b2Ed3C2...31320aC26
0.005 ETH0.0002072861470.00581188
Execute Order1155692542024-01-31 21:41:25312 days ago1706737285IN
0x9b2Ed3C2...31320aC26
0.001 ETH0.0002926466940.10017597
Execute Order1155686882024-01-31 21:22:33312 days ago1706736153IN
0x9b2Ed3C2...31320aC26
0 ETH0.0002585827850.10255127
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
1167884162024-02-29 3:00:09284 days ago1709175609
0x9b2Ed3C2...31320aC26
0.168308922665729 ETH
1167884162024-02-29 3:00:09284 days ago1709175609
0x9b2Ed3C2...31320aC26
0.168308922665729 ETH
1167580022024-02-28 10:06:21284 days ago1709114781
0x9b2Ed3C2...31320aC26
0.012344852680156 ETH
1167580022024-02-28 10:06:21284 days ago1709114781
0x9b2Ed3C2...31320aC26
0.012344852680156 ETH
1166889782024-02-26 19:45:33286 days ago1708976733
0x9b2Ed3C2...31320aC26
0.000545888902158 ETH
1166889782024-02-26 19:45:33286 days ago1708976733
0x9b2Ed3C2...31320aC26
0.000545888902158 ETH
1164625302024-02-21 13:57:17291 days ago1708523837
0x9b2Ed3C2...31320aC26
0.00997 ETH
1164625302024-02-21 13:57:17291 days ago1708523837
0x9b2Ed3C2...31320aC26
0.00997 ETH
1164249502024-02-20 17:04:37292 days ago1708448677
0x9b2Ed3C2...31320aC26
0.288393502275037 ETH
1164249502024-02-20 17:04:37292 days ago1708448677
0x9b2Ed3C2...31320aC26
0.288393502275037 ETH
1164202652024-02-20 14:28:27292 days ago1708439307
0x9b2Ed3C2...31320aC26
0.111361671216484 ETH
1164202652024-02-20 14:28:27292 days ago1708439307
0x9b2Ed3C2...31320aC26
0.111361671216484 ETH
1164201992024-02-20 14:26:15292 days ago1708439175
0x9b2Ed3C2...31320aC26
0.04944151247388 ETH
1164201992024-02-20 14:26:15292 days ago1708439175
0x9b2Ed3C2...31320aC26
0.04944151247388 ETH
1164175692024-02-20 12:58:35292 days ago1708433915
0x9b2Ed3C2...31320aC26
0.095575688775016 ETH
1164175692024-02-20 12:58:35292 days ago1708433915
0x9b2Ed3C2...31320aC26
0.095575688775016 ETH
1164174772024-02-20 12:55:31292 days ago1708433731
0x9b2Ed3C2...31320aC26
0.055940216360902 ETH
1164174772024-02-20 12:55:31292 days ago1708433731
0x9b2Ed3C2...31320aC26
0.055940216360902 ETH
1164135182024-02-20 10:43:33292 days ago1708425813
0x9b2Ed3C2...31320aC26
0.015943179831649 ETH
1164135182024-02-20 10:43:33292 days ago1708425813
0x9b2Ed3C2...31320aC26
0.015943179831649 ETH
1164133462024-02-20 10:37:49292 days ago1708425469
0x9b2Ed3C2...31320aC26
0.162590213386406 ETH
1164133462024-02-20 10:37:49292 days ago1708425469
0x9b2Ed3C2...31320aC26
0.162590213386406 ETH
1163725282024-02-19 11:57:13293 days ago1708343833
0x9b2Ed3C2...31320aC26
0.000513333598954 ETH
1163725282024-02-19 11:57:13293 days ago1708343833
0x9b2Ed3C2...31320aC26
0.000513333598954 ETH
1163700802024-02-19 10:35:37293 days ago1708338937
0x9b2Ed3C2...31320aC26
0.00004985 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WidoRouter

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 2000 runs

Other Settings:
default evmVersion
File 1 of 11 : WidoRouter.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.7;

import "solmate/src/utils/SafeTransferLib.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IWidoRouter.sol";
import "./WidoTokenManager.sol";

error SlippageTooHigh(uint256 expectedAmount, uint256 actualAmount);

/// @title Wido Router
/// @notice Zap in or out of any ERC20 token, liquid or illiquid, in a single transaction.
/// @notice DO NOT APPROVE THIS CONTRACT FOR SPENDING YOUR TOKENS.
/// @author Wido
contract WidoRouter is IWidoRouter, Ownable, ReentrancyGuard {
    using SafeTransferLib for address;
    using SafeTransferLib for ERC20;

    bytes32 private constant EIP712_DOMAIN_TYPEHASH =
        keccak256(
            abi.encodePacked("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
        );

    bytes32 private constant ORDER_TYPEHASH =
        keccak256(
            abi.encodePacked(
                "Order(OrderInput[] inputs,OrderOutput[] outputs,address user,uint32 nonce,uint32 expiration)OrderInput(address tokenAddress,uint256 amount)OrderOutput(address tokenAddress,uint256 minOutputAmount)"
            )
        );

    bytes32 private constant ORDER_INPUT_TYPEHASH =
        keccak256(abi.encodePacked("OrderInput(address tokenAddress,uint256 amount)"));

    bytes32 private constant ORDER_OUTPUT_TYPEHASH =
        keccak256(abi.encodePacked("OrderOutput(address tokenAddress,uint256 minOutputAmount)"));

    // Nonce for executing order with EIP-712 signatures.
    mapping(address => uint256) public nonces;

    // Address of the wrapped native token
    address public immutable wrappedNativeToken;

    // Address of fee bank
    address public bank;

    WidoTokenManager public immutable widoTokenManager;

    /// @notice Event emitted when the order is fulfilled
    /// @param order The order that was fulfilled
    /// @param sender The msg.sender
    /// @param recipient Recipient of the final tokens of the order
    /// @param feeBps Fee in basis points (bps)
    /// @param partner Partner address
    event FulfilledOrder(
        Order order,
        address indexed sender,
        address recipient,
        uint256 feeBps,
        address indexed partner
    );

    /// @notice Event emitted when the bank address is updated
    /// @param bank The updated address of the bank
    event SetBank(
        address bank
    );

    constructor(
        address _wrappedNativeToken,
        address _bank // uint256 _feeBps
    ) {
        require(_wrappedNativeToken != address(0) && _bank != address(0), "Addresses cannot be zero address");

        wrappedNativeToken = _wrappedNativeToken;
        bank = _bank;
        widoTokenManager = new WidoTokenManager();
    }

    /// @notice Sets the bank address
    /// @param _bank The address of the new bank
    function setBank(address _bank) external onlyOwner {
        require(_bank != address(0) && _bank != address(this), "Bank address cannot be zero address or Wido Router address");
        bank = _bank;
        emit SetBank(_bank);
    }

    /// @notice Approve a token spending
    /// @param token The ERC20 token to approve
    /// @param spender The address of the spender
    /// @param amount The minimum allowance to grant to the spender
    function _approveToken(address token, address spender, uint256 amount) internal {
        ERC20 _token = ERC20(token);
        if (_token.allowance(address(this), spender) < amount) {
            _token.safeApprove(spender, type(uint256).max);
        }
    }

    /// @notice Executes steps in the route to transfer to token
    /// @param route Step data for token transformation
    /// @dev Updates the amount in the byte data with the current balance as to not leave any dust
    /// @dev Expects step data to be properly chained for the token transformation tokenA -> tokenB -> tokenC
    function _executeSteps(Step[] calldata route) private {
        for (uint256 i = 0; i < route.length; ) {
            Step calldata step = route[i];

            require(step.targetAddress != address(widoTokenManager), "Wido: forbidden call to WidoTokenManager");

            uint256 balance;
            uint256 value;
            if (step.fromToken == address(0)) {
                value = address(this).balance;
            } else {
                value = 0;
                balance = ERC20(step.fromToken).balanceOf(address(this));
                require(balance > 0, "Not enough balance for the step");
                _approveToken(step.fromToken, step.targetAddress, balance);
            }

            bytes memory editedSwapData;
            if (step.amountIndex >= 0) {
                uint256 idx = uint256(int256(step.amountIndex));
                editedSwapData = bytes.concat(step.data[:idx], abi.encode(balance), step.data[idx + 32:]);
            } else {
                editedSwapData = step.data;
            }

            (bool success, bytes memory result) = step.targetAddress.call{value: value}(editedSwapData);
            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            unchecked {
                i++;
            }
        }
    }

    function hash(OrderInput[] memory orderInput) internal pure returns (bytes32) {
        bytes32[] memory result = new bytes32[](orderInput.length);
        for (uint256 i = 0; i < orderInput.length; ) {
            result[i] = keccak256(abi.encode(ORDER_INPUT_TYPEHASH, orderInput[i]));
            unchecked {
                i++;
            }
        }
        return keccak256(abi.encodePacked(result));
    }

    function hash(OrderOutput[] memory orderOutput) internal pure returns (bytes32) {
        bytes32[] memory result = new bytes32[](orderOutput.length);
        for (uint256 i = 0; i < orderOutput.length; ) {
            result[i] = keccak256(abi.encode(ORDER_OUTPUT_TYPEHASH, orderOutput[i]));
            unchecked {
                i++;
            }
        }
        return keccak256(abi.encodePacked(result));
    }

    function hash(Order memory order) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    ORDER_TYPEHASH,
                    hash(order.inputs),
                    hash(order.outputs),
                    order.user,
                    order.nonce,
                    order.expiration
                )
            );
    }

    /// @notice Verifies if the order is valid
    /// @param order Order to be validated
    /// @param v v of the signature
    /// @param r r of the signature
    /// @param s s of the signature
    /// @return bool True if the order is valid
    function verifyOrder(Order calldata order, uint8 v, bytes32 r, bytes32 s) public view override returns (bool) {
        bytes32 DOMAIN_SEPARATOR = keccak256(
            abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256("WidoRouter"), keccak256("1"), block.chainid, address(this))
        );
        address recoveredAddress = ECDSA.recover(
            keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hash(order))),
            v,
            r,
            s
        );
        require(recoveredAddress != address(0) && order.user == recoveredAddress, "Invalid signature");
        require(order.nonce == nonces[order.user], "Invalid nonce");
        require(order.expiration == 0 || block.timestamp <= order.expiration, "Expired request");
        for (uint256 i = 0; i < order.inputs.length; ) {
            IWidoRouter.OrderInput calldata input = order.inputs[i];
            require(input.amount > 0, "Amount should be greater than 0");
            unchecked {
                i++;
            }
        }
        return true;
    }

    /// @notice Executes the validated order
    /// @param order Order to be executed
    /// @param route Route to execute for the token swap
    /// @param recipient The address of the final token receiver
    /// @param feeBps Fee in basis points (bps)
    /// @dev Expects the steps in the route to transform order.fromToken to order.toToken
    /// @dev Expects at least order.minToTokenAmount to be transferred to the recipient
    function _executeOrder(Order calldata order, Step[] calldata route, address recipient, uint256 feeBps) private {
        widoTokenManager.pullTokens(order.user, order.inputs);

        for (uint256 i = 0; i < order.inputs.length; ) {
            IWidoRouter.OrderInput calldata input = order.inputs[i];

            uint256 balance;
            if (input.tokenAddress == address(0)) {
                balance = address(this).balance;
            } else {
                balance = ERC20(input.tokenAddress).balanceOf(address(this));
            }
            require(balance >= input.amount, "Balance lower than order amount");
            _collectFees(input.tokenAddress, balance, feeBps);

            unchecked {
                i++;
            }
        }

        _executeSteps(route);

        for (uint256 i = 0; i < order.outputs.length; ) {
            IWidoRouter.OrderOutput calldata output = order.outputs[i];

            if (output.tokenAddress == address(0)) {
                uint256 balance = address(this).balance;
                if (balance < output.minOutputAmount) {
                    revert SlippageTooHigh(output.minOutputAmount, balance);
                }
                recipient.safeTransferETH(balance);
            } else {
                uint256 balance = ERC20(output.tokenAddress).balanceOf(address(this));
                if (balance < output.minOutputAmount) {
                    revert SlippageTooHigh(output.minOutputAmount, balance);
                }
                ERC20(output.tokenAddress).safeTransfer(recipient, balance);
            }

            unchecked {
                i++;
            }
        }
    }

    /// @notice Returns the amount of tokens or native tokens after accounting for fee
    /// @param fromToken Address of the token for the fee
    /// @param amount Amount of tokens to subtract the fee
    /// @param feeBps Fee in basis points (bps)
    /// @dev Sends the fee to the bank to not maintain any balance in the contract
    function _collectFees(address fromToken, uint256 amount, uint256 feeBps) private {
        require(feeBps <= 100, "Fee out of range");
        uint256 fee = (amount * feeBps) / 10000;
        if (fee > 0) {
            if (fromToken == address(0)) {
                bank.safeTransferETH(fee);
            } else {
                ERC20(fromToken).safeTransfer(bank, fee);
            }
        }
    }

    /// @notice Executes order to transform ERC20 token from order.fromToken to order.toToken
    /// @param order Order describing the expectation of the token transformation
    /// @param route Route describes the details of the token transformation
    /// @param feeBps Fee in basis points (bps)
    /// @param partner Partner address
    function executeOrder(
        Order calldata order,
        Step[] calldata route,
        uint256 feeBps,
        address partner
    ) external payable override nonReentrant {
        require(msg.sender == order.user, "Invalid order user");
        _executeOrder(order, route, order.user, feeBps);
        emit FulfilledOrder(order, msg.sender, order.user, feeBps, partner);
    }

    /// @notice Executes order to transform ERC20 token from order.fromToken to order.toToken
    /// @param order Order describing the expectation of the token transformation
    /// @param route Route describes the details of the token transformation
    /// @param recipient Destination address where the final tokens are sent
    /// @param feeBps Fee in basis points (bps)
    /// @param partner Partner address
    function executeOrder(
        Order calldata order,
        Step[] calldata route,
        address recipient,
        uint256 feeBps,
        address partner
    ) external payable override nonReentrant {
        require(msg.sender == order.user, "Invalid order user");
        _executeOrder(order, route, recipient, feeBps);
        emit FulfilledOrder(order, msg.sender, recipient, feeBps, partner);
    }

    /// @notice Executes the order with valid EIP-712 signature
    /// @param order Order describing the expectation of the token transformation
    /// @param route Expects a valid route to transform order.fromToken to order.toToken
    /// @param v v of the signature
    /// @param r r of the signature
    /// @param s s of the signation
    /// @param feeBps Fee in basis points (bps)
    /// @param partner Partner address
    function executeOrderWithSignature(
        Order calldata order,
        Step[] calldata route,
        uint8 v,
        bytes32 r,
        bytes32 s,
        uint256 feeBps,
        address partner
    ) external override nonReentrant {
        require(verifyOrder(order, v, r, s), "Invalid order");
        nonces[order.user]++;
        _executeOrder(order, route, order.user, feeBps);
        emit FulfilledOrder(order, msg.sender, order.user, feeBps, partner);
    }

    /// @notice Allow receiving of native tokens
    receive() external payable {}
}

File 2 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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 Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        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 3 of 11 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 4 of 11 : 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 5 of 11 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 6 of 11 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 7 of 11 : IWidoRouter.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.7;

interface IWidoRouter {
    /// @notice OrderInput object describing the desired token inputs
    /// @param tokenAddress Address of the input token
    /// @param fromTokenAmount Amount of the input token to spend on the user's behalf
    /// @dev amount must == msg.value when token == address(0)
    struct OrderInput {
        address tokenAddress;
        uint256 amount;
    }

    /// @notice OrderOutput object describing the desired token outputs
    /// @param tokenAddress Address of the output token
    /// @param minOutputAmount Minimum amount of the output token the user is willing to accept for this order
    struct OrderOutput {
        address tokenAddress;
        uint256 minOutputAmount;
    }

    /// @notice Order object describing the requirements of the zap
    /// @param inputs Array of input objects, see OrderInput
    /// @param outputs Array of output objects, see OrderOutput
    /// @param user Address of user placing the order
    /// @param nonce Number used once to ensure an order requested by a signature only executes once
    /// @param expiration Timestamp until which the order is valid to execute
    struct Order {
        OrderInput[] inputs;
        OrderOutput[] outputs;
        address user;
        uint32 nonce;
        uint32 expiration;
    }

    /// @notice Step object describing a single token transformation
    /// @param fromToken Address of the from token
    /// @param targetAddress Address of the contract performing the transformation
    /// @param data Data which the swap contract will be called with
    /// @param amountIndex Index for the from token amount that can be found in data and needs to be updated with the most recent value.
    struct Step {
        address fromToken;
        address targetAddress;
        bytes data;
        int32 amountIndex;
    }

    function verifyOrder(Order calldata order, uint8 v, bytes32 r, bytes32 s) external view returns (bool);

    function executeOrder(
        Order calldata order,
        Step[] calldata route,
        uint256 feeBps,
        address partner
    ) external payable;

    function executeOrder(
        Order calldata order,
        Step[] calldata route,
        address recipient,
        uint256 feeBps,
        address partner
    ) external payable;

    function executeOrderWithSignature(
        Order calldata order,
        Step[] calldata route,
        uint8 v,
        bytes32 r,
        bytes32 s,
        uint256 feeBps,
        address partner
    ) external;
}

File 8 of 11 : IWidoTokenManager.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.7;
import "./IWidoRouter.sol";

interface IWidoTokenManager {
    function pullTokens(address user, IWidoRouter.OrderInput[] calldata inputs) external;
}

File 9 of 11 : WidoTokenManager.sol
// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.7;

import "solmate/src/utils/SafeTransferLib.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IWidoTokenManager.sol";

contract WidoTokenManager is IWidoTokenManager, Ownable {
    using SafeTransferLib for ERC20;

    /// @notice Transfers tokens or native tokens from the user
    /// @param user The address of the order user
    /// @param inputs Array of input objects, see OrderInput and Order
    function pullTokens(address user, IWidoRouter.OrderInput[] calldata inputs) external override onlyOwner {
        for (uint256 i = 0; i < inputs.length; i++) {
            IWidoRouter.OrderInput calldata input = inputs[i];

            if (input.tokenAddress == address(0)) {
                continue;
            }

            ERC20(input.tokenAddress).safeTransferFrom(user, owner(), input.amount);
        }
    }
}

File 10 of 11 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 11 of 11 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 2000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_wrappedNativeToken","type":"address"},{"internalType":"address","name":"_bank","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"expectedAmount","type":"uint256"},{"internalType":"uint256","name":"actualAmount","type":"uint256"}],"name":"SlippageTooHigh","type":"error"},{"anonymous":false,"inputs":[{"components":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderInput[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderOutput[]","name":"outputs","type":"tuple[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiration","type":"uint32"}],"indexed":false,"internalType":"struct IWidoRouter.Order","name":"order","type":"tuple"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeBps","type":"uint256"},{"indexed":true,"internalType":"address","name":"partner","type":"address"}],"name":"FulfilledOrder","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":"bank","type":"address"}],"name":"SetBank","type":"event"},{"inputs":[],"name":"bank","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderInput[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderOutput[]","name":"outputs","type":"tuple[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiration","type":"uint32"}],"internalType":"struct IWidoRouter.Order","name":"order","type":"tuple"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"int32","name":"amountIndex","type":"int32"}],"internalType":"struct IWidoRouter.Step[]","name":"route","type":"tuple[]"},{"internalType":"uint256","name":"feeBps","type":"uint256"},{"internalType":"address","name":"partner","type":"address"}],"name":"executeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderInput[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderOutput[]","name":"outputs","type":"tuple[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiration","type":"uint32"}],"internalType":"struct IWidoRouter.Order","name":"order","type":"tuple"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"int32","name":"amountIndex","type":"int32"}],"internalType":"struct IWidoRouter.Step[]","name":"route","type":"tuple[]"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBps","type":"uint256"},{"internalType":"address","name":"partner","type":"address"}],"name":"executeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderInput[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderOutput[]","name":"outputs","type":"tuple[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiration","type":"uint32"}],"internalType":"struct IWidoRouter.Order","name":"order","type":"tuple"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"int32","name":"amountIndex","type":"int32"}],"internalType":"struct IWidoRouter.Step[]","name":"route","type":"tuple[]"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"feeBps","type":"uint256"},{"internalType":"address","name":"partner","type":"address"}],"name":"executeOrderWithSignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bank","type":"address"}],"name":"setBank","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderInput[]","name":"inputs","type":"tuple[]"},{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"minOutputAmount","type":"uint256"}],"internalType":"struct IWidoRouter.OrderOutput[]","name":"outputs","type":"tuple[]"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"uint32","name":"expiration","type":"uint32"}],"internalType":"struct IWidoRouter.Order","name":"order","type":"tuple"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"verifyOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"widoTokenManager","outputs":[{"internalType":"contract WidoTokenManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wrappedNativeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b5060405162003189380380620031898339810160408190526200003491620001a2565b6200003f3362000127565b600180556001600160a01b038216158015906200006457506001600160a01b03811615155b620000b55760405162461bcd60e51b815260206004820181905260248201527f4164647265737365732063616e6e6f74206265207a65726f2061646472657373604482015260640160405180910390fd5b606082901b6001600160601b031916608052600380546001600160a01b0319166001600160a01b038316179055604051620000f09062000177565b604051809103906000f0801580156200010d573d6000803e3d6000fd5b5060601b6001600160601b03191660a05250620001da9050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6105cd8062002bbc83390190565b80516001600160a01b03811681146200019d57600080fd5b919050565b60008060408385031215620001b657600080fd5b620001c18362000185565b9150620001d16020840162000185565b90509250929050565b60805160601c60a05160601c6129a8620002146000396000818161015c01528181610e9e01526118c00152600061010b01526129a86000f3fe6080604052600436106100cb5760003560e01c80637ecebe0011610074578063e58610841161004e578063e58610841461024f578063f2fde38b1461026f578063fc171d911461028f57600080fd5b80637ecebe00146101e35780638da5cb5b1461021e578063916a3bd91461023c57600080fd5b80633967048b116100a55780633967048b1461017e578063715018a6146101ae57806376cdb03b146101c357600080fd5b8063090d23b9146100d757806317fcb39b146100f95780631802553e1461014a57600080fd5b366100d257005b600080fd5b3480156100e357600080fd5b506100f76100f2366004612025565b6102a2565b005b34801561010557600080fd5b5061012d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015657600080fd5b5061012d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018a57600080fd5b5061019e6101993660046122be565b6103ae565b6040519015158152602001610141565b3480156101ba57600080fd5b506100f761076b565b3480156101cf57600080fd5b5060035461012d906001600160a01b031681565b3480156101ef57600080fd5b506102106101fe366004612025565b60026020526000908152604090205481565b604051908152602001610141565b34801561022a57600080fd5b506000546001600160a01b031661012d565b6100f761024a366004612192565b61077f565b34801561025b57600080fd5b506100f761026a366004612216565b6108c3565b34801561027b57600080fd5b506100f761028a366004612025565b610a2d565b6100f761029d3660046120fe565b610abd565b6102aa610bed565b6001600160a01b038116158015906102cb57506001600160a01b0381163014155b6103425760405162461bcd60e51b815260206004820152603a60248201527f42616e6b20616464726573732063616e6e6f74206265207a65726f206164647260448201527f657373206f72205769646f20526f75746572206164647265737300000000000060648201526084015b60405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f10f5824683d64a0712038f2244e046b174a1cc57fbb8556bfda5ffb2612440679060200160405180910390a150565b600080604051602001610430907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060208201527f766572696679696e67436f6e7472616374290000000000000000000000000000604082015260520190565b60408051601f198184030181528282528051602091820120908301527fe18799aceb0d5c1134b671173b8112a3ebcbe15aaef1b5bf23f47082a09df0ec908201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c001604051602081830303815290604052805190602001209050600061052d826104d6896104d1906127cf565b610c47565b6040517f190100000000000000000000000000000000000000000000000000000000000060208201526022810192909252604282015260620160405160208183030381529060405280519060200120878787610e04565b90506001600160a01b0381161580159061056757506001600160a01b03811661055c6060890160408a01612025565b6001600160a01b0316145b6105b35760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610339565b600260006105c760608a0160408b01612025565b6001600160a01b031681526020810191909152604001600020546105f16080890160608a01612334565b63ffffffff16146106445760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610339565b61065460a0880160808901612334565b63ffffffff16158061067b575061067160a0880160808901612334565b63ffffffff164211155b6106c75760405162461bcd60e51b815260206004820152600f60248201527f45787069726564207265717565737400000000000000000000000000000000006044820152606401610339565b60005b6106d488806125c0565b905081101561075d57366106e889806125c0565b838181106106f8576106f8612946565b905060400201905060008160200135116107545760405162461bcd60e51b815260206004820152601f60248201527f416d6f756e742073686f756c642062652067726561746572207468616e2030006044820152606401610339565b506001016106ca565b506001979650505050505050565b610773610bed565b61077d6000610e2c565b565b600260015414156107d25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b60026001556107e76060860160408701612025565b6001600160a01b0316336001600160a01b0316146108475760405162461bcd60e51b815260206004820152601260248201527f496e76616c6964206f72646572207573657200000000000000000000000000006044820152606401610339565b61086385858561085d6060840160408501612025565b86610e94565b6001600160a01b038116337f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb9091876108a06060820160408301612025565b866040516108b0939291906124b8565b60405180910390a3505060018055505050565b600260015414156109165760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b6002600155610927888686866103ae565b6109735760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206f72646572000000000000000000000000000000000000006044820152606401610339565b6002600061098760608b0160408c01612025565b6001600160a01b03168152602081019190915260400160009081208054916109ae836128ff565b909155506109ca905088888861085d6060840160408501612025565b6001600160a01b038116337f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb90918a610a076060820160408301612025565b86604051610a17939291906124b8565b60405180910390a3505060018055505050505050565b610a35610bed565b6001600160a01b038116610ab15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610339565b610aba81610e2c565b50565b60026001541415610b105760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b6002600155610b256060870160408801612025565b6001600160a01b0316336001600160a01b031614610b855760405162461bcd60e51b815260206004820152601260248201527f496e76616c6964206f72646572207573657200000000000000000000000000006044820152606401610339565b610b928686868686610e94565b806001600160a01b0316336001600160a01b03167f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb9091888686604051610bd9939291906124b8565b60405180910390a350506001805550505050565b6000546001600160a01b0316331461077d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610339565b6000604051602001610d60907f4f72646572284f72646572496e7075745b5d20696e707574732c4f726465724f81527f75747075745b5d206f7574707574732c6164647265737320757365722c75696e60208201527f743332206e6f6e63652c75696e7433322065787069726174696f6e294f72646560408201527f72496e707574286164647265737320746f6b656e416464726573732c75696e7460608201527f32353620616d6f756e74294f726465724f75747075742861646472657373207460808201527f6f6b656e416464726573732c75696e74323536206d696e4f7574707574416d6f60a08201527f756e74290000000000000000000000000000000000000000000000000000000060c082015260c40190565b60405160208183030381529060405280519060200120610d838360000151611267565b610d9084602001516113c1565b604080860151606087015160808801519251610de79695949390602001958652602086019490945260408501929092526001600160a01b0316606084015263ffffffff90811660808401521660a082015260c00190565b604051602081830303815290604052805190602001209050919050565b6000806000610e15878787876114eb565b91509150610e22816115d8565b5095945050505050565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166377fc3fa8610ed36060880160408901612025565b610edd88806125c0565b6040518463ffffffff1660e01b8152600401610efb93929190612432565b600060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b5050505060005b610f3a86806125c0565b905081101561108d5736610f4e87806125c0565b83818110610f5e57610f5e612946565b6040029190910191506000905080610f796020840184612025565b6001600160a01b03161415610f8f575047611018565b610f9c6020830183612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610fdd57600080fd5b505afa158015610ff1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611015919061231b565b90505b816020013581101561106c5760405162461bcd60e51b815260206004820152601f60248201527f42616c616e6365206c6f776572207468616e206f7264657220616d6f756e74006044820152606401610339565b61108361107c6020840184612025565b82866117c9565b5050600101610f30565b506110988484611884565b60005b6110a860208701876125c0565b905081101561125f57366110bf60208801886125c0565b838181106110cf576110cf612946565b604002919091019150600090506110e96020830183612025565b6001600160a01b0316141561115d57476020820135811015611144576040517f76baadda0000000000000000000000000000000000000000000000000000000081526020830135600482015260248101829052604401610339565b6111576001600160a01b03861682611c60565b50611256565b600061116c6020830183612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b1580156111ad57600080fd5b505afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061231b565b90508160200135811015611232576040517f76baadda0000000000000000000000000000000000000000000000000000000081526020830135600482015260248101829052604401610339565b61125485826112446020860186612025565b6001600160a01b03169190611cbb565b505b5060010161109b565b505050505050565b600080825167ffffffffffffffff8111156112845761128461295c565b6040519080825280602002602001820160405280156112ad578160200160208202803683370190505b50905060005b835181101561139157604051602001611315907f4f72646572496e707574286164647265737320746f6b656e416464726573732c81527f75696e7432353620616d6f756e742900000000000000000000000000000000006020820152602f0190565b6040516020818303038152906040528051906020012084828151811061133d5761133d612946565b602002602001015160405160200161135692919061245e565b6040516020818303038152906040528051906020012082828151811061137e5761137e612946565b60209081029190910101526001016112b3565b50806040516020016113a391906123ac565b60405160208183030381529060405280519060200120915050919050565b600080825167ffffffffffffffff8111156113de576113de61295c565b604051908082528060200260200182016040528015611407578160200160208202803683370190505b50905060005b83518110156113915760405160200161146f907f4f726465724f7574707574286164647265737320746f6b656e4164647265737381527f2c75696e74323536206d696e4f7574707574416d6f756e742900000000000000602082015260390190565b6040516020818303038152906040528051906020012084828151811061149757611497612946565b60200260200101516040516020016114b092919061245e565b604051602081830303815290604052805190602001208282815181106114d8576114d8612946565b602090810291909101015260010161140d565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561152257506000905060036115cf565b8460ff16601b1415801561153a57508460ff16601c14155b1561154b57506000905060046115cf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561159f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166115c8576000600192509250506115cf565b9150600090505b94509492505050565b60008160048111156115ec576115ec612930565b14156115f55750565b600181600481111561160957611609612930565b14156116575760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610339565b600281600481111561166b5761166b612930565b14156116b95760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610339565b60038160048111156116cd576116cd612930565b14156117415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610339565b600481600481111561175557611755612930565b1415610aba5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610339565b606481111561181a5760405162461bcd60e51b815260206004820152601060248201527f466565206f7574206f662072616e6765000000000000000000000000000000006044820152606401610339565b600061271061182983856127b0565b611833919061278e565b9050801561187e576001600160a01b0384166118645760035461185f906001600160a01b031682611c60565b61187e565b60035461187e906001600160a01b03868116911683611cbb565b50505050565b60005b81811015611c5b57368383838181106118a2576118a2612946565b90506020028101906118b49190612651565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166118f06040830160208401612025565b6001600160a01b0316141561196d5760405162461bcd60e51b815260206004820152602860248201527f5769646f3a20666f7262696464656e2063616c6c20746f205769646f546f6b6560448201527f6e4d616e616765720000000000000000000000000000000000000000000000006064820152608401610339565b6000808061197e6020850185612025565b6001600160a01b03161415611994575047611a95565b5060006119a46020840184612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b1580156119e557600080fd5b505afa1580156119f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1d919061231b565b915060008211611a6f5760405162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f7567682062616c616e636520666f72207468652073746570006044820152606401610339565b611a95611a7f6020850185612025565b611a8f6040860160208701612025565b84611d5a565b60606000611aa860808601868401612047565b60030b12611b4b576000611ac26080860160608701612047565b60030b9050611ad4604086018661260a565b611ae291839160009161274c565b60408051602081018890520160408051601f19818403018152918152611b0a9089018961260a565b611b15866020612776565b611b2092829061274c565b604051602001611b349594939291906123e2565b604051602081830303815290604052915050611b90565b611b58604085018561260a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b600080611ba36040870160208801612025565b6001600160a01b03168484604051611bbb9190612416565b60006040518083038185875af1925050503d8060008114611bf8576040519150601f19603f3d011682016040523d82523d6000602084013e611bfd565b606091505b509150915081611c4957604481511015611c1657600080fd5b60048101905080806020019051810190611c30919061206a565b60405162461bcd60e51b81526004016103399190612485565b50506001909401935061188792505050565b505050565b600080600080600085875af1905080611c5b5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610339565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061187e5760405162461bcd60e51b815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610339565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301528491839183169063dd62ed3e9060440160206040518083038186803b158015611dbe57600080fd5b505afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df6919061231b565b101561187e5761187e6001600160a01b0382168460001960006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061187e5760405162461bcd60e51b815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610339565b80356001600160a01b0381168114611ec357600080fd5b919050565b600082601f830112611ed957600080fd5b81356020611eee611ee9836126df565b6126ae565b80838252828201915082860187848660061b8901011115611f0e57600080fd5b60005b85811015611f3857611f238983611f91565b84529284019260409190910190600101611f11565b5090979650505050505050565b60008083601f840112611f5757600080fd5b50813567ffffffffffffffff811115611f6f57600080fd5b6020830191508360208260051b8501011115611f8a57600080fd5b9250929050565b600060408284031215611fa357600080fd5b6040516040810181811067ffffffffffffffff82111715611fc657611fc661295c565b604052905080611fd583611eac565b8152602083013560208201525092915050565b600060a08284031215611ffa57600080fd5b50919050565b803563ffffffff81168114611ec357600080fd5b803560ff81168114611ec357600080fd5b60006020828403121561203757600080fd5b61204082611eac565b9392505050565b60006020828403121561205957600080fd5b81358060030b811461204057600080fd5b60006020828403121561207c57600080fd5b815167ffffffffffffffff8082111561209457600080fd5b818401915084601f8301126120a857600080fd5b8151818111156120ba576120ba61295c565b6120cd6020601f19601f840116016126ae565b91508082528560208285010111156120e457600080fd5b6120f58160208401602086016128d3565b50949350505050565b60008060008060008060a0878903121561211757600080fd5b863567ffffffffffffffff8082111561212f57600080fd5b61213b8a838b01611fe8565b9750602089013591508082111561215157600080fd5b5061215e89828a01611f45565b9096509450612171905060408801611eac565b92506060870135915061218660808801611eac565b90509295509295509295565b6000806000806000608086880312156121aa57600080fd5b853567ffffffffffffffff808211156121c257600080fd5b6121ce89838a01611fe8565b965060208801359150808211156121e457600080fd5b506121f188828901611f45565b9095509350506040860135915061220a60608701611eac565b90509295509295909350565b60008060008060008060008060e0898b03121561223257600080fd5b883567ffffffffffffffff8082111561224a57600080fd5b6122568c838d01611fe8565b995060208b013591508082111561226c57600080fd5b506122798b828c01611f45565b909850965061228c905060408a01612014565b9450606089013593506080890135925060a089013591506122af60c08a01611eac565b90509295985092959890939650565b600080600080608085870312156122d457600080fd5b843567ffffffffffffffff8111156122eb57600080fd5b6122f787828801611fe8565b94505061230660208601612014565b93969395505050506040820135916060013590565b60006020828403121561232d57600080fd5b5051919050565b60006020828403121561234657600080fd5b61204082612000565b81835260208301925060008160005b8481101561238357612370868361238d565b604095860195919091019060010161235e565b5093949350505050565b6001600160a01b0361239e82611eac565b168252602090810135910152565b815160009082906020808601845b838110156123d6578151855293820193908201906001016123ba565b50929695505050505050565b8486823760008582016000815285516123ff818360208a016128d3565b018385823760009301928352509095945050505050565b600082516124288184602087016128d3565b9190910192915050565b6001600160a01b038416815260406020820152600061245560408301848661234f565b95945050505050565b82815260608101612040602083018480516001600160a01b03168252602090810151910152565b60208152600082518060208401526124a48160408501602087016128d3565b601f01601f19169190910160400192915050565b6060815260006124c88586612703565b60a060608501526124de6101008501828461234f565b9150506124ee6020870187612703565b8483037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa00160808601528083529091600091906020015b8183101561254a57612537818561238d565b6040938401936001939093019201612525565b61255660408a01611eac565b6001600160a01b03811660a0880152935061257360608a01612000565b63ffffffff811660c0880152935061258d60808a01612000565b63ffffffff1660e08701526001600160a01b038816602087015293506125b292505050565b826040830152949350505050565b6000808335601e198436030181126125d757600080fd5b83018035915067ffffffffffffffff8211156125f257600080fd5b6020019150600681901b3603821315611f8a57600080fd5b6000808335601e1984360301811261262157600080fd5b83018035915067ffffffffffffffff82111561263c57600080fd5b602001915036819003821315611f8a57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261242857600080fd5b60405160a0810167ffffffffffffffff811182821017156126a8576126a861295c565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d7576126d761295c565b604052919050565b600067ffffffffffffffff8211156126f9576126f961295c565b5060051b60200190565b6000808335601e1984360301811261271a57600080fd5b830160208101925035905067ffffffffffffffff81111561273a57600080fd5b8060061b3603831315611f8a57600080fd5b6000808585111561275c57600080fd5b8386111561276957600080fd5b5050820193919092039150565b600082198211156127895761278961291a565b500190565b6000826127ab57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156127ca576127ca61291a565b500290565b600060a082360312156127e157600080fd5b6127e9612685565b823567ffffffffffffffff8082111561280157600080fd5b9084019036601f83011261281457600080fd5b81356020612824611ee9836126df565b8281528181019085830136600686901b88018501111561284357600080fd5b600096505b8487101561286f5761285a3682611f91565b83526001969096019591830191604001612848565b508652508681013593508284111561288657600080fd5b61289236858901611ec8565b81860152505050506128a660408401611eac565b60408201526128b760608401612000565b60608201526128c860808401612000565b608082015292915050565b60005b838110156128ee5781810151838201526020016128d6565b8381111561187e5750506000910152565b60006000198214156129135761291361291a565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122050ff5cabe47edd9569ce89e0ba0f68eff813e85d665e712a723440f1d6f5cc4564736f6c63430008070033608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61054f8061007e6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063715018a61461005157806377fc3fa81461005b5780638da5cb5b1461006e578063f2fde38b1461009a575b600080fd5b6100596100ad565b005b610059610069366004610404565b6100c1565b6000546040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100596100a83660046103e2565b61018f565b6100b5610231565b6100bf6000610298565b565b6100c9610231565b60005b8181101561018957368383838181106100e7576100e76104ea565b6040029190910191506000905061010160208301836103e2565b73ffffffffffffffffffffffffffffffffffffffff1614156101235750610177565b6101758561014660005473ffffffffffffffffffffffffffffffffffffffff1690565b6020840180359061015790866103e2565b73ffffffffffffffffffffffffffffffffffffffff1692919061030d565b505b806101818161048a565b9150506100cc565b50505050565b610197610231565b73ffffffffffffffffffffffffffffffffffffffff81166102255760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61022e81610298565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146100bf5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161021c565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806103b25760405162461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640161021c565b5050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146103dd57600080fd5b919050565b6000602082840312156103f457600080fd5b6103fd826103b9565b9392505050565b60008060006040848603121561041957600080fd5b610422846103b9565b9250602084013567ffffffffffffffff8082111561043f57600080fd5b818601915086601f83011261045357600080fd5b81358181111561046257600080fd5b8760208260061b850101111561047757600080fd5b6020830194508093505050509250925092565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156104e3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea26469706673582212204dd1f47161d778557eea8c911bac4fd310ad7cc96f57ff7b36fb2fe38010b82464736f6c6343000807003300000000000000000000000042000000000000000000000000000000000000060000000000000000000000005ef7f250f74d4f11a68054ae4e150705474a6d4a

Deployed Bytecode

0x6080604052600436106100cb5760003560e01c80637ecebe0011610074578063e58610841161004e578063e58610841461024f578063f2fde38b1461026f578063fc171d911461028f57600080fd5b80637ecebe00146101e35780638da5cb5b1461021e578063916a3bd91461023c57600080fd5b80633967048b116100a55780633967048b1461017e578063715018a6146101ae57806376cdb03b146101c357600080fd5b8063090d23b9146100d757806317fcb39b146100f95780631802553e1461014a57600080fd5b366100d257005b600080fd5b3480156100e357600080fd5b506100f76100f2366004612025565b6102a2565b005b34801561010557600080fd5b5061012d7f000000000000000000000000420000000000000000000000000000000000000681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015657600080fd5b5061012d7f000000000000000000000000c1ae663b4b4d211b4f865dc36a0db36ffcf7152881565b34801561018a57600080fd5b5061019e6101993660046122be565b6103ae565b6040519015158152602001610141565b3480156101ba57600080fd5b506100f761076b565b3480156101cf57600080fd5b5060035461012d906001600160a01b031681565b3480156101ef57600080fd5b506102106101fe366004612025565b60026020526000908152604090205481565b604051908152602001610141565b34801561022a57600080fd5b506000546001600160a01b031661012d565b6100f761024a366004612192565b61077f565b34801561025b57600080fd5b506100f761026a366004612216565b6108c3565b34801561027b57600080fd5b506100f761028a366004612025565b610a2d565b6100f761029d3660046120fe565b610abd565b6102aa610bed565b6001600160a01b038116158015906102cb57506001600160a01b0381163014155b6103425760405162461bcd60e51b815260206004820152603a60248201527f42616e6b20616464726573732063616e6e6f74206265207a65726f206164647260448201527f657373206f72205769646f20526f75746572206164647265737300000000000060648201526084015b60405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f10f5824683d64a0712038f2244e046b174a1cc57fbb8556bfda5ffb2612440679060200160405180910390a150565b600080604051602001610430907f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c616464726573732060208201527f766572696679696e67436f6e7472616374290000000000000000000000000000604082015260520190565b60408051601f198184030181528282528051602091820120908301527fe18799aceb0d5c1134b671173b8112a3ebcbe15aaef1b5bf23f47082a09df0ec908201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c001604051602081830303815290604052805190602001209050600061052d826104d6896104d1906127cf565b610c47565b6040517f190100000000000000000000000000000000000000000000000000000000000060208201526022810192909252604282015260620160405160208183030381529060405280519060200120878787610e04565b90506001600160a01b0381161580159061056757506001600160a01b03811661055c6060890160408a01612025565b6001600160a01b0316145b6105b35760405162461bcd60e51b815260206004820152601160248201527f496e76616c6964207369676e61747572650000000000000000000000000000006044820152606401610339565b600260006105c760608a0160408b01612025565b6001600160a01b031681526020810191909152604001600020546105f16080890160608a01612334565b63ffffffff16146106445760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610339565b61065460a0880160808901612334565b63ffffffff16158061067b575061067160a0880160808901612334565b63ffffffff164211155b6106c75760405162461bcd60e51b815260206004820152600f60248201527f45787069726564207265717565737400000000000000000000000000000000006044820152606401610339565b60005b6106d488806125c0565b905081101561075d57366106e889806125c0565b838181106106f8576106f8612946565b905060400201905060008160200135116107545760405162461bcd60e51b815260206004820152601f60248201527f416d6f756e742073686f756c642062652067726561746572207468616e2030006044820152606401610339565b506001016106ca565b506001979650505050505050565b610773610bed565b61077d6000610e2c565b565b600260015414156107d25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b60026001556107e76060860160408701612025565b6001600160a01b0316336001600160a01b0316146108475760405162461bcd60e51b815260206004820152601260248201527f496e76616c6964206f72646572207573657200000000000000000000000000006044820152606401610339565b61086385858561085d6060840160408501612025565b86610e94565b6001600160a01b038116337f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb9091876108a06060820160408301612025565b866040516108b0939291906124b8565b60405180910390a3505060018055505050565b600260015414156109165760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b6002600155610927888686866103ae565b6109735760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206f72646572000000000000000000000000000000000000006044820152606401610339565b6002600061098760608b0160408c01612025565b6001600160a01b03168152602081019190915260400160009081208054916109ae836128ff565b909155506109ca905088888861085d6060840160408501612025565b6001600160a01b038116337f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb90918a610a076060820160408301612025565b86604051610a17939291906124b8565b60405180910390a3505060018055505050505050565b610a35610bed565b6001600160a01b038116610ab15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610339565b610aba81610e2c565b50565b60026001541415610b105760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610339565b6002600155610b256060870160408801612025565b6001600160a01b0316336001600160a01b031614610b855760405162461bcd60e51b815260206004820152601260248201527f496e76616c6964206f72646572207573657200000000000000000000000000006044820152606401610339565b610b928686868686610e94565b806001600160a01b0316336001600160a01b03167f1ac24a2fc0a341cfcb02105ee08de6110d72cdf0d2b78fe9136f5da301eb9091888686604051610bd9939291906124b8565b60405180910390a350506001805550505050565b6000546001600160a01b0316331461077d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610339565b6000604051602001610d60907f4f72646572284f72646572496e7075745b5d20696e707574732c4f726465724f81527f75747075745b5d206f7574707574732c6164647265737320757365722c75696e60208201527f743332206e6f6e63652c75696e7433322065787069726174696f6e294f72646560408201527f72496e707574286164647265737320746f6b656e416464726573732c75696e7460608201527f32353620616d6f756e74294f726465724f75747075742861646472657373207460808201527f6f6b656e416464726573732c75696e74323536206d696e4f7574707574416d6f60a08201527f756e74290000000000000000000000000000000000000000000000000000000060c082015260c40190565b60405160208183030381529060405280519060200120610d838360000151611267565b610d9084602001516113c1565b604080860151606087015160808801519251610de79695949390602001958652602086019490945260408501929092526001600160a01b0316606084015263ffffffff90811660808401521660a082015260c00190565b604051602081830303815290604052805190602001209050919050565b6000806000610e15878787876114eb565b91509150610e22816115d8565b5095945050505050565b600080546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b037f000000000000000000000000c1ae663b4b4d211b4f865dc36a0db36ffcf71528166377fc3fa8610ed36060880160408901612025565b610edd88806125c0565b6040518463ffffffff1660e01b8152600401610efb93929190612432565b600060405180830381600087803b158015610f1557600080fd5b505af1158015610f29573d6000803e3d6000fd5b5050505060005b610f3a86806125c0565b905081101561108d5736610f4e87806125c0565b83818110610f5e57610f5e612946565b6040029190910191506000905080610f796020840184612025565b6001600160a01b03161415610f8f575047611018565b610f9c6020830183612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610fdd57600080fd5b505afa158015610ff1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611015919061231b565b90505b816020013581101561106c5760405162461bcd60e51b815260206004820152601f60248201527f42616c616e6365206c6f776572207468616e206f7264657220616d6f756e74006044820152606401610339565b61108361107c6020840184612025565b82866117c9565b5050600101610f30565b506110988484611884565b60005b6110a860208701876125c0565b905081101561125f57366110bf60208801886125c0565b838181106110cf576110cf612946565b604002919091019150600090506110e96020830183612025565b6001600160a01b0316141561115d57476020820135811015611144576040517f76baadda0000000000000000000000000000000000000000000000000000000081526020830135600482015260248101829052604401610339565b6111576001600160a01b03861682611c60565b50611256565b600061116c6020830183612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b1580156111ad57600080fd5b505afa1580156111c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e5919061231b565b90508160200135811015611232576040517f76baadda0000000000000000000000000000000000000000000000000000000081526020830135600482015260248101829052604401610339565b61125485826112446020860186612025565b6001600160a01b03169190611cbb565b505b5060010161109b565b505050505050565b600080825167ffffffffffffffff8111156112845761128461295c565b6040519080825280602002602001820160405280156112ad578160200160208202803683370190505b50905060005b835181101561139157604051602001611315907f4f72646572496e707574286164647265737320746f6b656e416464726573732c81527f75696e7432353620616d6f756e742900000000000000000000000000000000006020820152602f0190565b6040516020818303038152906040528051906020012084828151811061133d5761133d612946565b602002602001015160405160200161135692919061245e565b6040516020818303038152906040528051906020012082828151811061137e5761137e612946565b60209081029190910101526001016112b3565b50806040516020016113a391906123ac565b60405160208183030381529060405280519060200120915050919050565b600080825167ffffffffffffffff8111156113de576113de61295c565b604051908082528060200260200182016040528015611407578160200160208202803683370190505b50905060005b83518110156113915760405160200161146f907f4f726465724f7574707574286164647265737320746f6b656e4164647265737381527f2c75696e74323536206d696e4f7574707574416d6f756e742900000000000000602082015260390190565b6040516020818303038152906040528051906020012084828151811061149757611497612946565b60200260200101516040516020016114b092919061245e565b604051602081830303815290604052805190602001208282815181106114d8576114d8612946565b602090810291909101015260010161140d565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561152257506000905060036115cf565b8460ff16601b1415801561153a57508460ff16601c14155b1561154b57506000905060046115cf565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561159f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166115c8576000600192509250506115cf565b9150600090505b94509492505050565b60008160048111156115ec576115ec612930565b14156115f55750565b600181600481111561160957611609612930565b14156116575760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610339565b600281600481111561166b5761166b612930565b14156116b95760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610339565b60038160048111156116cd576116cd612930565b14156117415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610339565b600481600481111561175557611755612930565b1415610aba5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610339565b606481111561181a5760405162461bcd60e51b815260206004820152601060248201527f466565206f7574206f662072616e6765000000000000000000000000000000006044820152606401610339565b600061271061182983856127b0565b611833919061278e565b9050801561187e576001600160a01b0384166118645760035461185f906001600160a01b031682611c60565b61187e565b60035461187e906001600160a01b03868116911683611cbb565b50505050565b60005b81811015611c5b57368383838181106118a2576118a2612946565b90506020028101906118b49190612651565b90506001600160a01b037f000000000000000000000000c1ae663b4b4d211b4f865dc36a0db36ffcf71528166118f06040830160208401612025565b6001600160a01b0316141561196d5760405162461bcd60e51b815260206004820152602860248201527f5769646f3a20666f7262696464656e2063616c6c20746f205769646f546f6b6560448201527f6e4d616e616765720000000000000000000000000000000000000000000000006064820152608401610339565b6000808061197e6020850185612025565b6001600160a01b03161415611994575047611a95565b5060006119a46020840184612025565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b1580156119e557600080fd5b505afa1580156119f9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1d919061231b565b915060008211611a6f5760405162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f7567682062616c616e636520666f72207468652073746570006044820152606401610339565b611a95611a7f6020850185612025565b611a8f6040860160208701612025565b84611d5a565b60606000611aa860808601868401612047565b60030b12611b4b576000611ac26080860160608701612047565b60030b9050611ad4604086018661260a565b611ae291839160009161274c565b60408051602081018890520160408051601f19818403018152918152611b0a9089018961260a565b611b15866020612776565b611b2092829061274c565b604051602001611b349594939291906123e2565b604051602081830303815290604052915050611b90565b611b58604085018561260a565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b600080611ba36040870160208801612025565b6001600160a01b03168484604051611bbb9190612416565b60006040518083038185875af1925050503d8060008114611bf8576040519150601f19603f3d011682016040523d82523d6000602084013e611bfd565b606091505b509150915081611c4957604481511015611c1657600080fd5b60048101905080806020019051810190611c30919061206a565b60405162461bcd60e51b81526004016103399190612485565b50506001909401935061188792505050565b505050565b600080600080600085875af1905080611c5b5760405162461bcd60e51b815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401610339565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061187e5760405162461bcd60e51b815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610339565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0383811660248301528491839183169063dd62ed3e9060440160206040518083038186803b158015611dbe57600080fd5b505afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df6919061231b565b101561187e5761187e6001600160a01b0382168460001960006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061187e5760405162461bcd60e51b815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610339565b80356001600160a01b0381168114611ec357600080fd5b919050565b600082601f830112611ed957600080fd5b81356020611eee611ee9836126df565b6126ae565b80838252828201915082860187848660061b8901011115611f0e57600080fd5b60005b85811015611f3857611f238983611f91565b84529284019260409190910190600101611f11565b5090979650505050505050565b60008083601f840112611f5757600080fd5b50813567ffffffffffffffff811115611f6f57600080fd5b6020830191508360208260051b8501011115611f8a57600080fd5b9250929050565b600060408284031215611fa357600080fd5b6040516040810181811067ffffffffffffffff82111715611fc657611fc661295c565b604052905080611fd583611eac565b8152602083013560208201525092915050565b600060a08284031215611ffa57600080fd5b50919050565b803563ffffffff81168114611ec357600080fd5b803560ff81168114611ec357600080fd5b60006020828403121561203757600080fd5b61204082611eac565b9392505050565b60006020828403121561205957600080fd5b81358060030b811461204057600080fd5b60006020828403121561207c57600080fd5b815167ffffffffffffffff8082111561209457600080fd5b818401915084601f8301126120a857600080fd5b8151818111156120ba576120ba61295c565b6120cd6020601f19601f840116016126ae565b91508082528560208285010111156120e457600080fd5b6120f58160208401602086016128d3565b50949350505050565b60008060008060008060a0878903121561211757600080fd5b863567ffffffffffffffff8082111561212f57600080fd5b61213b8a838b01611fe8565b9750602089013591508082111561215157600080fd5b5061215e89828a01611f45565b9096509450612171905060408801611eac565b92506060870135915061218660808801611eac565b90509295509295509295565b6000806000806000608086880312156121aa57600080fd5b853567ffffffffffffffff808211156121c257600080fd5b6121ce89838a01611fe8565b965060208801359150808211156121e457600080fd5b506121f188828901611f45565b9095509350506040860135915061220a60608701611eac565b90509295509295909350565b60008060008060008060008060e0898b03121561223257600080fd5b883567ffffffffffffffff8082111561224a57600080fd5b6122568c838d01611fe8565b995060208b013591508082111561226c57600080fd5b506122798b828c01611f45565b909850965061228c905060408a01612014565b9450606089013593506080890135925060a089013591506122af60c08a01611eac565b90509295985092959890939650565b600080600080608085870312156122d457600080fd5b843567ffffffffffffffff8111156122eb57600080fd5b6122f787828801611fe8565b94505061230660208601612014565b93969395505050506040820135916060013590565b60006020828403121561232d57600080fd5b5051919050565b60006020828403121561234657600080fd5b61204082612000565b81835260208301925060008160005b8481101561238357612370868361238d565b604095860195919091019060010161235e565b5093949350505050565b6001600160a01b0361239e82611eac565b168252602090810135910152565b815160009082906020808601845b838110156123d6578151855293820193908201906001016123ba565b50929695505050505050565b8486823760008582016000815285516123ff818360208a016128d3565b018385823760009301928352509095945050505050565b600082516124288184602087016128d3565b9190910192915050565b6001600160a01b038416815260406020820152600061245560408301848661234f565b95945050505050565b82815260608101612040602083018480516001600160a01b03168252602090810151910152565b60208152600082518060208401526124a48160408501602087016128d3565b601f01601f19169190910160400192915050565b6060815260006124c88586612703565b60a060608501526124de6101008501828461234f565b9150506124ee6020870187612703565b8483037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa00160808601528083529091600091906020015b8183101561254a57612537818561238d565b6040938401936001939093019201612525565b61255660408a01611eac565b6001600160a01b03811660a0880152935061257360608a01612000565b63ffffffff811660c0880152935061258d60808a01612000565b63ffffffff1660e08701526001600160a01b038816602087015293506125b292505050565b826040830152949350505050565b6000808335601e198436030181126125d757600080fd5b83018035915067ffffffffffffffff8211156125f257600080fd5b6020019150600681901b3603821315611f8a57600080fd5b6000808335601e1984360301811261262157600080fd5b83018035915067ffffffffffffffff82111561263c57600080fd5b602001915036819003821315611f8a57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261242857600080fd5b60405160a0810167ffffffffffffffff811182821017156126a8576126a861295c565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d7576126d761295c565b604052919050565b600067ffffffffffffffff8211156126f9576126f961295c565b5060051b60200190565b6000808335601e1984360301811261271a57600080fd5b830160208101925035905067ffffffffffffffff81111561273a57600080fd5b8060061b3603831315611f8a57600080fd5b6000808585111561275c57600080fd5b8386111561276957600080fd5b5050820193919092039150565b600082198211156127895761278961291a565b500190565b6000826127ab57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156127ca576127ca61291a565b500290565b600060a082360312156127e157600080fd5b6127e9612685565b823567ffffffffffffffff8082111561280157600080fd5b9084019036601f83011261281457600080fd5b81356020612824611ee9836126df565b8281528181019085830136600686901b88018501111561284357600080fd5b600096505b8487101561286f5761285a3682611f91565b83526001969096019591830191604001612848565b508652508681013593508284111561288657600080fd5b61289236858901611ec8565b81860152505050506128a660408401611eac565b60408201526128b760608401612000565b60608201526128c860808401612000565b608082015292915050565b60005b838110156128ee5781810151838201526020016128d6565b8381111561187e5750506000910152565b60006000198214156129135761291361291a565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122050ff5cabe47edd9569ce89e0ba0f68eff813e85d665e712a723440f1d6f5cc4564736f6c63430008070033

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

00000000000000000000000042000000000000000000000000000000000000060000000000000000000000005ef7f250f74d4f11a68054ae4e150705474a6d4a

-----Decoded View---------------
Arg [0] : _wrappedNativeToken (address): 0x4200000000000000000000000000000000000006
Arg [1] : _bank (address): 0x5EF7F250f74d4F11A68054AE4e150705474a6D4a

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [1] : 0000000000000000000000005ef7f250f74d4f11a68054ae4e150705474a6d4a


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
[ 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.