ETH Price: $2,322.27 (+0.33%)
Gas: 0.11 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute Orders184665212023-10-31 0:22:47825 days ago1698711767IN
0x007105D2...44606E34a
0 ETH0.0141828139.59345379

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60a06040184361152023-10-26 18:15:59830 days ago1698344159  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LimitOrders

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 100000 runs

Other Settings:
london EvmVersion
/// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {Auth, Authority} from "solmate/auth/Auth.sol";
import {TransferHelper} from "src/lib/TransferHelper.sol";
import {FullMath} from "src/lib/FullMath.sol";
import {IBondAggregator} from "src/interfaces/IBondAggregator.sol";
import {IBondAuctioneer} from "src/interfaces/IBondAuctioneer.sol";
import {IBondTeller} from "src/interfaces/IBondTeller.sol";

contract LimitOrders is Auth {
    using TransferHelper for ERC20;
    using FullMath for uint256;

    /* ========== EVENTS ========== */
    event OrderExecuted(bytes32 digest);
    event OrderCancelled(bytes32 digest);
    event OrderReinstated(bytes32 digest);

    /* ========== ERRORS ========== */
    error LimitOrders_NotAuthorized();
    error LimitOrders_OrderExpired(uint256 deadline);
    error LimitOrders_MarketClosed(uint256 marketId);
    error LimitOrders_AlreadyExecuted(bytes32 digest);
    error LimitOrders_OrderCancelled(bytes32 digest);
    error LimitOrders_InvalidUpdate();
    error LimitOrders_InvalidFee(uint256 fee, uint256 maxFee);
    error LimitOrders_InvalidSignature(bytes signature);
    error LimitOrders_InvalidParams();
    error LimitOrders_InvalidUser();

    /* ========== STATE ========== */

    struct Order {
        uint256 marketId;
        address recipient;
        address referrer;
        uint256 amount;
        uint256 minAmountOut;
        uint256 maxFee;
        uint256 submitted;
        uint256 deadline;
        address user;
    }

    enum Status {
        Open,
        Executed,
        Cancelled
    }

    IBondAggregator public immutable aggregator;

    uint256 public chainId;
    bytes32 internal domainSeparator;

    bytes32 internal constant ORDER_TYPEHASH =
        keccak256(
            "Order(uint256 marketId,address recipient,address referrer,uint256 amount,uint256 minAmountOut,uint256 maxFee,uint256 submitted,uint256 deadline,address user)"
        );

    mapping(bytes32 => Status) public orderStatus;

    /* ========== CONSTRUCTOR ========== */

    constructor(IBondAggregator aggregator_, Authority authority_) Auth(address(0), authority_) {
        aggregator = aggregator_;
        chainId = block.chainid;
        domainSeparator = computeDomainSeparator();
    }

    /* ========== ORDER EXECUTION ========== */

    function executeOrders(
        Order[] calldata orders_,
        bytes[] calldata signatures_,
        uint256[] calldata fees_
    ) external requiresAuth {
        uint256 len = orders_.length;
        if (len != fees_.length || len != signatures_.length) revert LimitOrders_InvalidParams();

        for (uint256 i; i < len; ) {
            _executeOrder(orders_[i], signatures_[i], fees_[i]);
            unchecked {
                ++i;
            }
        }
    }

    function executeOrder(
        Order calldata order_,
        bytes calldata signature_,
        uint256 fee_
    ) external requiresAuth {
        _executeOrder(order_, signature_, fee_);
    }

    function _executeOrder(
        Order calldata order_,
        bytes calldata signature_,
        uint256 fee_
    ) internal {
        // Validate order
        bytes32 digest = _validateOrder(order_, signature_);

        // Validate that the order has not expired
        if (order_.deadline < block.timestamp) revert LimitOrders_OrderExpired(order_.deadline);

        // Validate that the market is still active
        if (!aggregator.isLive(order_.marketId)) revert LimitOrders_MarketClosed(order_.marketId);

        // Validate that the order has not already been executed
        // and that the user has not cancelled the order
        Status status = orderStatus[digest];
        if (status == Status.Executed) revert LimitOrders_AlreadyExecuted(digest);
        if (status == Status.Cancelled) revert LimitOrders_OrderCancelled(digest);

        // Confirm that executor fee is within bounds and calculate amount minus fee
        if (fee_ > order_.maxFee) revert LimitOrders_InvalidFee(fee_, order_.maxFee);
        uint256 amount = order_.amount - fee_;

        // Mark the order as executed
        orderStatus[digest] = Status.Executed;

        // Get max amount accepted for market
        uint256 maxAccepted = aggregator.maxAmountAccepted(order_.marketId, order_.referrer);

        // Set the amount for the purchase as the lesser of the order amount and the max accepted
        uint256 minAmountOut = order_.minAmountOut;
        if (amount > maxAccepted) {
            // If amount is too large, set to max accepted
            amount = maxAccepted;

            // We need to convert the new amount to an equivalent payout amount
            // The minAmountOut represents the price the user is willing to pay per token
            // after the max fee is taken out.
            if (minAmountOut != 0) {
                uint256 scale = aggregator.marketScale(order_.marketId);
                uint256 maxPrice = (order_.amount - order_.maxFee).mulDiv(
                    scale,
                    order_.minAmountOut
                );
                minAmountOut = amount.mulDiv(scale, maxPrice);
            }
        }

        // Transfer tokens from user to this contract for the purchase
        IBondAuctioneer auctioneer = aggregator.getAuctioneer(order_.marketId);
        (, , , ERC20 quoteToken, , ) = auctioneer.getMarketInfoForPurchase(order_.marketId);
        quoteToken.safeTransferFrom(order_.user, address(this), amount + fee_);

        // Approve teller to spend token
        IBondTeller teller = auctioneer.getTeller();
        quoteToken.safeApprove(address(teller), amount);

        // Execute purchase
        teller.purchase(order_.recipient, order_.referrer, order_.marketId, amount, minAmountOut);

        // Transfer fee to executor
        quoteToken.safeTransfer(msg.sender, fee_);

        // Emit event for off-chain service to pick up
        emit OrderExecuted(digest);
    }

    function _validateOrder(
        Order calldata order_,
        bytes calldata signature_
    ) internal view returns (bytes32) {
        // Validate the user is not the zero address (must do this to avoid bypassing the signer check)
        // Although, transfers from the zero address would later fail in _executeOrder, so it may not be necessary
        if (order_.user == address(0)) revert LimitOrders_InvalidUser();
        if (signature_.length != 65) revert LimitOrders_InvalidSignature(signature_);

        // Get order digest
        bytes32 digest = getDigest(order_);

        // Validate signature
        bytes32 r = bytes32(signature_[0:32]);
        bytes32 s = bytes32(signature_[32:64]);
        uint8 v = uint8(signature_[64]);
        address signer = ecrecover(digest, v, r, s);

        if (signer != order_.user) revert LimitOrders_InvalidSignature(signature_);

        return digest;
    }

    function getDigest(Order calldata order_) public view returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    hex"1901",
                    DOMAIN_SEPARATOR(),
                    keccak256(
                        abi.encode(
                            ORDER_TYPEHASH,
                            order_.marketId,
                            order_.recipient,
                            order_.referrer,
                            order_.amount,
                            order_.minAmountOut,
                            order_.maxFee,
                            order_.submitted,
                            order_.deadline,
                            order_.user
                        )
                    )
                )
            );
    }

    /* ========== USER FUNCTIONS ========== */

    function cancelOrder(Order calldata order_) external {
        // Validate that the sender is the order "user"
        if (msg.sender != order_.user) revert LimitOrders_NotAuthorized();

        // Validate that the order has not expired (no need to cancel if so)
        if (order_.deadline < block.timestamp) revert LimitOrders_OrderExpired(order_.deadline);

        // Get order digest
        bytes32 digest = getDigest(order_);

        // Validate that the order has not already been executed
        // and that the user has not cancelled the order
        if (orderStatus[digest] != Status.Open) revert LimitOrders_InvalidUpdate();

        // Set order status to cancelled
        orderStatus[digest] = Status.Cancelled;

        // Emit event to pick up with off-chain service
        emit OrderCancelled(digest);
    }

    function reinstateOrder(Order calldata order_) external {
        // Validate that the sender is the order "user"
        if (msg.sender != order_.user) revert LimitOrders_NotAuthorized();

        // Validate that the order has not expired
        if (order_.deadline < block.timestamp) revert LimitOrders_OrderExpired(order_.deadline);

        // Get order digest
        bytes32 digest = getDigest(order_);

        // Validate that the order is currently cancelled
        if (orderStatus[digest] != Status.Cancelled) revert LimitOrders_InvalidUpdate();

        // Set the order status as open
        orderStatus[digest] = Status.Open;
    }

    /* ========== DOMAIN SEPARATOR ========== */

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

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256("Bond Protocol Limit Orders"),
                    keccak256("v1.0.0"),
                    block.chainid,
                    address(this)
                )
            );
    }

    function updateDomainSeparator() external {
        require(block.chainid != chainId, "DOMAIN_SEPARATOR_ALREADY_UPDATED");

        chainId = block.chainid;

        domainSeparator = computeDomainSeparator();
    }
}

// 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/Rari-Capital/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
    //////////////////////////////////////////////////////////////*/

    bytes32 public constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    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 {
            bytes32 digest = keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR(),
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );

            address recoveredAddress = ecrecover(digest, 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);
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
    event OwnerUpdated(address indexed user, address indexed newOwner);

    event AuthorityUpdated(address indexed user, Authority indexed newAuthority);

    address public owner;

    Authority public authority;

    constructor(address _owner, Authority _authority) {
        owner = _owner;
        authority = _authority;

        emit OwnerUpdated(msg.sender, _owner);
        emit AuthorityUpdated(msg.sender, _authority);
    }

    modifier requiresAuth() {
        require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");

        _;
    }

    function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
        return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
    }

    function setAuthority(Authority newAuthority) public virtual {
        // We check if the caller is the owner first because we want to ensure they can
        // always swap out the authority even if it's reverting or using up a lot of gas.
        require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));

        authority = newAuthority;

        emit AuthorityUpdated(msg.sender, newAuthority);
    }

    function setOwner(address newOwner) public virtual requiresAuth {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}

/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
    function canCall(
        address user,
        address target,
        bytes4 functionSig
    ) external view returns (bool);
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

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

/// @notice Safe ERC20 and ETH transfer library that safely handles missing return values.
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/libraries/TransferHelper.sol)
/// @author Taken from Solmate.
library TransferHelper {
    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.transferFrom.selector, from, to, amount)
        );

        require(
            success &&
                (data.length == 0 || abi.decode(data, (bool))) &&
                address(token).code.length > 0,
            "TRANSFER_FROM_FAILED"
        );
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.transfer.selector, to, amount)
        );

        require(
            success &&
                (data.length == 0 || abi.decode(data, (bool))) &&
                address(token).code.length > 0,
            "TRANSFER_FAILED"
        );
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(ERC20.approve.selector, to, amount)
        );

        require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
    }

    // function safeTransferETH(address to, uint256 amount) internal {
    //     (bool success, ) = to.call{value: amount}(new bytes(0));

    //     require(success, "ETH_TRANSFER_FAILED");
    // }
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (type(uint256).max - denominator + 1) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use Newton-Raphson iteration to improve the precision.
            // Thanks to Hensel's lifting lemma, this also works in modular
            // arithmetic, doubling the correct bits in each step.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // Because the division is now exact we can divide by multiplying
            // with the modular inverse of denominator. This will give us the
            // correct result modulo 2**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        result = mulDiv(a, b, denominator);
        unchecked {
            if (mulmod(a, b, denominator) > 0) {
                require(result < type(uint256).max);
                result++;
            }
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {IBondAuctioneer} from "../interfaces/IBondAuctioneer.sol";
import {IBondTeller} from "../interfaces/IBondTeller.sol";

interface IBondAggregator {
    /// @notice             Register a auctioneer with the aggregator
    /// @notice             Only Guardian
    /// @param auctioneer_  Address of the Auctioneer to register
    /// @dev                A auctioneer must be registered with an aggregator to create markets
    function registerAuctioneer(IBondAuctioneer auctioneer_) external;

    /// @notice             Register a new market with the aggregator
    /// @notice             Only registered depositories
    /// @param payoutToken_ Token to be paid out by the market
    /// @param quoteToken_  Token to be accepted by the market
    /// @param marketId     ID of the market being created
    function registerMarket(ERC20 payoutToken_, ERC20 quoteToken_)
        external
        returns (uint256 marketId);

    /// @notice     Get the auctioneer for the provided market ID
    /// @param id_  ID of Market
    function getAuctioneer(uint256 id_) external view returns (IBondAuctioneer);

    /// @notice             Calculate current market price of payout token in quote tokens
    /// @dev                Accounts for debt and control variable decay since last deposit (vs _marketPrice())
    /// @param id_          ID of market
    /// @return             Price for market (see the specific auctioneer for units)
    //
    // if price is below minimum price, minimum price is returned
    // this is enforced on deposits by manipulating total debt (see _decay())
    function marketPrice(uint256 id_) external view returns (uint256);

    /// @notice             Scale value to use when converting between quote token and payout token amounts with marketPrice()
    /// @param id_          ID of market
    /// @return             Scaling factor for market in configured decimals
    function marketScale(uint256 id_) external view returns (uint256);

    /// @notice             Payout due for amount of quote tokens
    /// @dev                Accounts for debt and control variable decay so it is up to date
    /// @param amount_      Amount of quote tokens to spend
    /// @param id_          ID of market
    /// @param referrer_    Address of referrer, used to get fees to calculate accurate payout amount.
    ///                     Inputting the zero address will take into account just the protocol fee.
    /// @return             amount of payout tokens to be paid
    function payoutFor(
        uint256 amount_,
        uint256 id_,
        address referrer_
    ) external view returns (uint256);

    /// @notice             Returns maximum amount of quote token accepted by the market
    /// @param id_          ID of market
    /// @param referrer_    Address of referrer, used to get fees to calculate accurate payout amount.
    ///                     Inputting the zero address will take into account just the protocol fee.
    function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256);

    /// @notice             Does market send payout immediately
    /// @param id_          Market ID to search for
    function isInstantSwap(uint256 id_) external view returns (bool);

    /// @notice             Is a given market accepting deposits
    /// @param id_          ID of market
    function isLive(uint256 id_) external view returns (bool);

    /// @notice             Returns array of active market IDs within a range
    /// @dev                Should be used if length exceeds max to query entire array
    function liveMarketsBetween(uint256 firstIndex_, uint256 lastIndex_)
        external
        view
        returns (uint256[] memory);

    /// @notice             Returns an array of all active market IDs for a given quote token
    /// @param token_       Address of token to query by
    /// @param isPayout_    If true, search by payout token, else search for quote token
    function liveMarketsFor(address token_, bool isPayout_)
        external
        view
        returns (uint256[] memory);

    /// @notice             Returns an array of all active market IDs for a given owner
    /// @param owner_       Address of owner to query by
    /// @param firstIndex_  Market ID to start at
    /// @param lastIndex_   Market ID to end at (non-inclusive)
    function liveMarketsBy(
        address owner_,
        uint256 firstIndex_,
        uint256 lastIndex_
    ) external view returns (uint256[] memory);

    /// @notice             Returns an array of all active market IDs for a given payout and quote token
    /// @param payout_      Address of payout token
    /// @param quote_       Address of quote token
    function marketsFor(address payout_, address quote_) external view returns (uint256[] memory);

    /// @notice                 Returns the market ID with the highest current payoutToken payout for depositing quoteToken
    /// @param payout_          Address of payout token
    /// @param quote_           Address of quote token
    /// @param amountIn_        Amount of quote tokens to deposit
    /// @param minAmountOut_    Minimum amount of payout tokens to receive as payout
    /// @param maxExpiry_       Latest acceptable vesting timestamp for bond
    ///                         Inputting the zero address will take into account just the protocol fee.
    function findMarketFor(
        address payout_,
        address quote_,
        uint256 amountIn_,
        uint256 minAmountOut_,
        uint256 maxExpiry_
    ) external view returns (uint256 id);

    /// @notice             Returns the Teller that services the market ID
    function getTeller(uint256 id_) external view returns (IBondTeller);

    /// @notice             Returns current capacity of a market
    function currentCapacity(uint256 id_) external view returns (uint256);
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {IBondTeller} from "../interfaces/IBondTeller.sol";
import {IBondAggregator} from "../interfaces/IBondAggregator.sol";

interface IBondAuctioneer {
    /// @notice                 Creates a new bond market
    /// @param params_          Configuration data needed for market creation, encoded in a bytes array
    /// @dev                    See specific auctioneer implementations for details on encoding the parameters.
    /// @return id              ID of new bond market
    function createMarket(bytes memory params_) external returns (uint256);

    /// @notice                 Disable existing bond market
    /// @notice                 Must be market owner
    /// @param id_              ID of market to close
    function closeMarket(uint256 id_) external;

    /// @notice                 Exchange quote tokens for a bond in a specified market
    /// @notice                 Must be teller
    /// @param id_              ID of the Market the bond is being purchased from
    /// @param amount_          Amount to deposit in exchange for bond (after fee has been deducted)
    /// @param minAmountOut_    Minimum acceptable amount of bond to receive. Prevents frontrunning
    /// @return payout          Amount of payout token to be received from the bond
    function purchaseBond(
        uint256 id_,
        uint256 amount_,
        uint256 minAmountOut_
    ) external returns (uint256 payout);

    /// @notice                         Set market intervals to different values than the defaults
    /// @notice                         Must be market owner
    /// @dev                            Changing the intervals could cause markets to behave in unexpected way
    ///                                 tuneInterval should be greater than tuneAdjustmentDelay
    /// @param id_                      Market ID
    /// @param intervals_               Array of intervals (3)
    ///                                 1. Tune interval - Frequency of tuning
    ///                                 2. Tune adjustment delay - Time to implement downward tuning adjustments
    ///                                 3. Debt decay interval - Interval over which debt should decay completely
    function setIntervals(uint256 id_, uint32[3] calldata intervals_) external;

    /// @notice                      Designate a new owner of a market
    /// @notice                      Must be market owner
    /// @dev                         Doesn't change permissions until newOwner calls pullOwnership
    /// @param id_                   Market ID
    /// @param newOwner_             New address to give ownership to
    function pushOwnership(uint256 id_, address newOwner_) external;

    /// @notice                      Accept ownership of a market
    /// @notice                      Must be market newOwner
    /// @dev                         The existing owner must call pushOwnership prior to the newOwner calling this function
    /// @param id_                   Market ID
    function pullOwnership(uint256 id_) external;

    /// @notice             Set the auctioneer defaults
    /// @notice             Must be policy
    /// @param defaults_    Array of default values
    ///                     1. Tune interval - amount of time between tuning adjustments
    ///                     2. Tune adjustment delay - amount of time to apply downward tuning adjustments
    ///                     3. Minimum debt decay interval - minimum amount of time to let debt decay to zero
    ///                     4. Minimum deposit interval - minimum amount of time to wait between deposits
    ///                     5. Minimum market duration - minimum amount of time a market can be created for
    ///                     6. Minimum debt buffer - the minimum amount of debt over the initial debt to trigger a market shutdown
    /// @dev                The defaults set here are important to avoid edge cases in market behavior, e.g. a very short market reacts doesn't tune well
    /// @dev                Only applies to new markets that are created after the change
    function setDefaults(uint32[6] memory defaults_) external;

    /// @notice             Change the status of the auctioneer to allow creation of new markets
    /// @dev                Setting to false and allowing active markets to end will sunset the auctioneer
    /// @param status_      Allow market creation (true) : Disallow market creation (false)
    function setAllowNewMarkets(bool status_) external;

    /// @notice             Change whether a market creator is allowed to use a callback address in their markets or not
    /// @notice             Must be guardian
    /// @dev                Callback is believed to be safe, but a whitelist is implemented to prevent abuse
    /// @param creator_     Address of market creator
    /// @param status_      Allow callback (true) : Disallow callback (false)
    function setCallbackAuthStatus(address creator_, bool status_) external;

    /* ========== VIEW FUNCTIONS ========== */

    /// @notice                 Provides information for the Teller to execute purchases on a Market
    /// @param id_              Market ID
    /// @return owner           Address of the market owner (tokens transferred from this address if no callback)
    /// @return callbackAddr    Address of the callback contract to get tokens for payouts
    /// @return payoutToken     Payout Token (token paid out) for the Market
    /// @return quoteToken      Quote Token (token received) for the Market
    /// @return vesting         Timestamp or duration for vesting, implementation-dependent
    /// @return maxPayout       Maximum amount of payout tokens you can purchase in one transaction
    function getMarketInfoForPurchase(uint256 id_)
        external
        view
        returns (
            address owner,
            address callbackAddr,
            ERC20 payoutToken,
            ERC20 quoteToken,
            uint48 vesting,
            uint256 maxPayout
        );

    /// @notice             Calculate current market price of payout token in quote tokens
    /// @param id_          ID of market
    /// @return             Price for market in configured decimals
    //
    // if price is below minimum price, minimum price is returned
    function marketPrice(uint256 id_) external view returns (uint256);

    /// @notice             Scale value to use when converting between quote token and payout token amounts with marketPrice()
    /// @param id_          ID of market
    /// @return             Scaling factor for market in configured decimals
    function marketScale(uint256 id_) external view returns (uint256);

    /// @notice             Payout due for amount of quote tokens
    /// @dev                Accounts for debt and control variable decay so it is up to date
    /// @param amount_      Amount of quote tokens to spend
    /// @param id_          ID of market
    /// @param referrer_    Address of referrer, used to get fees to calculate accurate payout amount.
    ///                     Inputting the zero address will take into account just the protocol fee.
    /// @return             amount of payout tokens to be paid
    function payoutFor(
        uint256 amount_,
        uint256 id_,
        address referrer_
    ) external view returns (uint256);

    /// @notice             Returns maximum amount of quote token accepted by the market
    /// @param id_          ID of market
    /// @param referrer_    Address of referrer, used to get fees to calculate accurate payout amount.
    ///                     Inputting the zero address will take into account just the protocol fee.
    function maxAmountAccepted(uint256 id_, address referrer_) external view returns (uint256);

    /// @notice             Does market send payout immediately
    /// @param id_          Market ID to search for
    function isInstantSwap(uint256 id_) external view returns (bool);

    /// @notice             Is a given market accepting deposits
    /// @param id_          ID of market
    function isLive(uint256 id_) external view returns (bool);

    /// @notice             Returns the address of the market owner
    /// @param id_          ID of market
    function ownerOf(uint256 id_) external view returns (address);

    /// @notice             Returns the Teller that services the Auctioneer
    function getTeller() external view returns (IBondTeller);

    /// @notice             Returns the Aggregator that services the Auctioneer
    function getAggregator() external view returns (IBondAggregator);

    /// @notice             Returns current capacity of a market
    function currentCapacity(uint256 id_) external view returns (uint256);
}

// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.0;

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

interface IBondTeller {
    /// @notice                 Exchange quote tokens for a bond in a specified market
    /// @param recipient_       Address of recipient of bond. Allows deposits for other addresses
    /// @param referrer_        Address of referrer who will receive referral fee. For frontends to fill.
    ///                         Direct calls can use the zero address for no referrer fee.
    /// @param id_              ID of the Market the bond is being purchased from
    /// @param amount_          Amount to deposit in exchange for bond
    /// @param minAmountOut_    Minimum acceptable amount of bond to receive. Prevents frontrunning
    /// @return                 Amount of payout token to be received from the bond
    /// @return                 Timestamp at which the bond token can be redeemed for the underlying token
    function purchase(
        address recipient_,
        address referrer_,
        uint256 id_,
        uint256 amount_,
        uint256 minAmountOut_
    ) external returns (uint256, uint48);

    /// @notice          Get current fee charged by the teller based on the combined protocol and referrer fee
    /// @param referrer_ Address of the referrer
    /// @return          Fee in basis points (3 decimal places)
    function getFee(address referrer_) external view returns (uint48);

    /// @notice         Set protocol fee
    /// @notice         Must be guardian
    /// @param fee_     Protocol fee in basis points (3 decimal places)
    function setProtocolFee(uint48 fee_) external;

    /// @notice          Set the discount for creating bond tokens from the base protocol fee
    /// @dev             The discount is subtracted from the protocol fee to determine the fee
    ///                  when using create() to mint bond tokens without using an Auctioneer
    /// @param discount_ Create Fee Discount in basis points (3 decimal places)
    function setCreateFeeDiscount(uint48 discount_) external;

    /// @notice         Set your fee as a referrer to the protocol
    /// @notice         Fee is set for sending address
    /// @param fee_     Referrer fee in basis points (3 decimal places)
    function setReferrerFee(uint48 fee_) external;

    /// @notice         Claim fees accrued by sender in the input tokens and sends them to the provided address
    /// @param tokens_  Array of tokens to claim fees for
    /// @param to_      Address to send fees to
    function claimFees(ERC20[] memory tokens_, address to_) external;
}

Settings
{
  "remappings": [
    "ds-test/=lib/ds-test/src/",
    "solmate/=lib/solmate/src/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "clones/=lib/clones-with-immutable-args/src/",
    "forge-std/=lib/forge-std/src/",
    "solidity-code-metrics/=node_modules/solidity-code-metrics/",
    "clones-with-immutable-args/=lib/clones-with-immutable-args/src/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "weird-erc20/=lib/solmate/lib/weird-erc20/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IBondAggregator","name":"aggregator_","type":"address"},{"internalType":"contract Authority","name":"authority_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"LimitOrders_AlreadyExecuted","type":"error"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"LimitOrders_InvalidFee","type":"error"},{"inputs":[],"name":"LimitOrders_InvalidParams","type":"error"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"LimitOrders_InvalidSignature","type":"error"},{"inputs":[],"name":"LimitOrders_InvalidUpdate","type":"error"},{"inputs":[],"name":"LimitOrders_InvalidUser","type":"error"},{"inputs":[{"internalType":"uint256","name":"marketId","type":"uint256"}],"name":"LimitOrders_MarketClosed","type":"error"},{"inputs":[],"name":"LimitOrders_NotAuthorized","type":"error"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"LimitOrders_OrderCancelled","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"LimitOrders_OrderExpired","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"OrderExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"OrderReinstated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggregator","outputs":[{"internalType":"contract IBondAggregator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"uint256","name":"submitted","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct LimitOrders.Order","name":"order_","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"uint256","name":"submitted","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct LimitOrders.Order","name":"order_","type":"tuple"},{"internalType":"bytes","name":"signature_","type":"bytes"},{"internalType":"uint256","name":"fee_","type":"uint256"}],"name":"executeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"uint256","name":"submitted","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct LimitOrders.Order[]","name":"orders_","type":"tuple[]"},{"internalType":"bytes[]","name":"signatures_","type":"bytes[]"},{"internalType":"uint256[]","name":"fees_","type":"uint256[]"}],"name":"executeOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"uint256","name":"submitted","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct LimitOrders.Order","name":"order_","type":"tuple"}],"name":"getDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orderStatus","outputs":[{"internalType":"enum LimitOrders.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"marketId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"},{"internalType":"uint256","name":"submitted","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"internalType":"struct LimitOrders.Order","name":"order_","type":"tuple"}],"name":"reinstateOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b50604051620025193803806200251983398101604081905262000034916200019f565b600080546001600160a01b03199081168255600180549091166001600160a01b0384161790556040518290829033907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908390a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350506001600160a01b038216608052466002556200017a604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f9718f7897be4857a1c4db401bfbda0cdc8360f3aa819b459203ddc8a51bf046d918101919091527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60035550620001de9050565b6001600160a01b03811681146200019c57600080fd5b50565b60008060408385031215620001b357600080fd5b8251620001c08162000186565b6020840151909250620001d38162000186565b809150509250929050565b608051612303620002166000396000818161010901528181610e6b015281816110850152818161119b015261128701526123036000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063816fae771161008c5780639a8a0592116100665780639a8a05921461020f578063bf7e214f14610218578063dc9cde9014610238578063ef734c881461024b57600080fd5b8063816fae77146101d457806389ccfe89146101e75780638da5cb5b146101ef57600080fd5b80633644e515116100c85780633644e51514610185578063501724001461019b5780636dfdff1a146101ae5780637a9e5e4b146101c157600080fd5b806313af4035146100ef578063245a7bfc146101045780632dff692d14610155575b600080fd5b6101026100fd366004611d58565b61025e565b005b61012b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610178610163366004611d75565b60046020526000908152604090205460ff1681565b60405161014c9190611dbd565b61018d610367565b60405190815260200161014c565b6101026101a9366004611e17565b610426565b6101026101bc366004611e34565b610580565b6101026101cf366004611d58565b610626565b61018d6101e2366004611e17565b610783565b6101026108d3565b60005461012b9073ffffffffffffffffffffffffffffffffffffffff1681565b61018d60025481565b60015461012b9073ffffffffffffffffffffffffffffffffffffffff1681565b610102610246366004611f0d565b6109ef565b610102610259366004611e17565b610b45565b61028c336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b6102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6000600254461461041f5761041a604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f9718f7897be4857a1c4db401bfbda0cdc8360f3aa819b459203ddc8a51bf046d918101919091527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060035490565b61043861012082016101008301611d58565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461049c576040517fd269887400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160e0013510156104e0576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e082013560048201526024016102ee565b60006104eb82610783565b9050600260008281526004602052604090205460ff16600281111561051257610512611d8e565b14610549576040517fcc4da24c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600090815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550565b6105ae336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102ee565b61062084848484610de9565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061070957506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff0000000000000000000000000000000000000000000000000000000016604482015273ffffffffffffffffffffffffffffffffffffffff9091169063b700961390606401602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611fd6565b61071257600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b600061078d610367565b7fee6d67b4f9cc8f0b2d8f722a450a03cc8283e7395eb38633d51e03342081899d83356107c06040860160208701611d58565b6107d06060870160408801611d58565b6060870135608088013560a089013560c08a013560e08b01356107fb6101208d016101008e01611d58565b60408051602081019b909b528a019890985273ffffffffffffffffffffffffffffffffffffffff96871660608a0152948616608089015260a088019390935260c087019190915260e08601526101008501526101208401521661014082015261016001604051602081830303815290604052805190602001206040516020016108b69291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050919050565b600254460361093e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444f4d41494e5f534550415241544f525f414c52454144595f5550444154454460448201526064016102ee565b466002556109ea604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f9718f7897be4857a1c4db401bfbda0cdc8360f3aa819b459203ddc8a51bf046d918101919091527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b600355565b610a1d336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b610a83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102ee565b848181141580610a935750808414155b15610aca576040517f84853dcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b3b57610b33888883818110610aea57610aea611ff8565b90506101200201878784818110610b0357610b03611ff8565b9050602002810190610b159190612027565b878786818110610b2757610b27611ff8565b90506020020135610de9565b600101610acd565b5050505050505050565b610b5761012082016101008301611d58565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bbb576040517fd269887400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160e001351015610bff576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e082013560048201526024016102ee565b6000610c0a82610783565b90506000808281526004602052604090205460ff166002811115610c3057610c30611d8e565b14610c67576040517fcc4da24c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600217905590518281527f5152abf959f6564662358c2e52b702259b78bac5ee7842a0f01937e670efcc7d910160405180910390a15050565b60015460009073ffffffffffffffffffffffffffffffffffffffff168015801590610dba57506040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b700961390606401602060405180830381865afa158015610d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dba9190611fd6565b80610ddf575060005473ffffffffffffffffffffffffffffffffffffffff8581169116145b9150505b92915050565b6000610df68585856115c9565b9050428560e001351015610e3c576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e086013560048201526024016102ee565b6040517f27507458000000000000000000000000000000000000000000000000000000008152853560048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632750745890602401602060405180830381865afa158015610ec7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eeb9190611fd6565b610f24576040517f08c51810000000000000000000000000000000000000000000000000000000008152853560048201526024016102ee565b60008181526004602052604090205460ff166001816002811115610f4a57610f4a611d8e565b03610f84576040517f9396c312000000000000000000000000000000000000000000000000000000008152600481018390526024016102ee565b6002816002811115610f9857610f98611d8e565b03610fd2576040517f1616126a000000000000000000000000000000000000000000000000000000008152600481018390526024016102ee565b8560a0013583111561101d576040517f8776a2030000000000000000000000000000000000000000000000000000000081526004810184905260a087013560248201526044016102ee565b600061102d8460608901356120bb565b600084815260046020526040902080549192506001917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682800217905550600073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663c7bf8ca089356110bc60608c0160408d01611d58565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561112b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114f91906120d2565b90506080880135818311156112555781925080600014611255576040517f946824cd000000000000000000000000000000000000000000000000000000008152893560048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063946824cd90602401602060405180830381865afa1580156111f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121b91906120d2565b90506000611243828c608001358d60a001358e6060013561123c91906120bb565b91906117cf565b90506112508583836117cf565b925050505b6040517f52047942000000000000000000000000000000000000000000000000000000008152893560048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635204794290602401602060405180830381865afa1580156112e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130791906120eb565b6040517facc5570c0000000000000000000000000000000000000000000000000000000081528b35600482015290915060009073ffffffffffffffffffffffffffffffffffffffff83169063acc5570c9060240160c060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c9190612123565b505093505050506113e48b6101000160208101906113ba9190611d58565b306113c58b8961219b565b73ffffffffffffffffffffffffffffffffffffffff851692919061189b565b60008273ffffffffffffffffffffffffffffffffffffffff16639787d1076040518163ffffffff1660e01b8152600401602060405180830381865afa158015611431573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145591906120eb565b905061147873ffffffffffffffffffffffffffffffffffffffff83168288611a37565b8073ffffffffffffffffffffffffffffffffffffffff16636de5b4cd8d60200160208101906114a79190611d58565b8e60400160208101906114ba9190611d58565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201528e356044820152606481018990526084810187905260a40160408051808303816000875af1158015611540573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156491906121b3565b50611588905073ffffffffffffffffffffffffffffffffffffffff8316338b611ba7565b6040518881527fc0688adab4193f84179a2fda51c33be35f0be04eda978b688bb1a41ce2c7e8469060200160405180910390a1505050505050505050505050565b6000806115de61012086016101008701611d58565b73ffffffffffffffffffffffffffffffffffffffff160361162b576040517fd697e28f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604182146116695782826040517f256d83e50000000000000000000000000000000000000000000000000000000081526004016102ee9291906121df565b600061167485610783565b90506000611685602082868861222c565b61168e91612256565b905060006116a060406020878961222c565b6116a991612256565b90506000868660408181106116c0576116c0611ff8565b604080516000808252602082018084528a9052949092013560f81c908201819052606082018790526080820186905293506001915060a0016020604051602081039080840390855afa15801561171a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151915061175890506101208a016101008b01611d58565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117c05787876040517f256d83e50000000000000000000000000000000000000000000000000000000081526004016102ee9291906121df565b509293505050505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003611826576000841161181b57600080fd5b5082900490506117c8565b80841161183257600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161193a9190612292565b6000604051808303816000865af19150503d8060008114611977576040519150601f19603f3d011682016040523d82523d6000602084013e61197c565b606091505b50915091508180156119a65750805115806119a65750808060200190518101906119a69190611fd6565b80156119c9575060008673ffffffffffffffffffffffffffffffffffffffff163b115b611a2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064016102ee565b505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151600092839290871691611ace9190612292565b6000604051808303816000865af19150503d8060008114611b0b576040519150601f19603f3d011682016040523d82523d6000602084013e611b10565b606091505b5091509150818015611b3a575080511580611b3a575080806020019051810190611b3a9190611fd6565b611ba0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c454400000000000000000000000000000000000060448201526064016102ee565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691611c3e9190612292565b6000604051808303816000865af19150503d8060008114611c7b576040519150601f19603f3d011682016040523d82523d6000602084013e611c80565b606091505b5091509150818015611caa575080511580611caa575080806020019051810190611caa9190611fd6565b8015611ccd575060008573ffffffffffffffffffffffffffffffffffffffff163b115b611ba0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016102ee565b73ffffffffffffffffffffffffffffffffffffffff81168114611d5557600080fd5b50565b600060208284031215611d6a57600080fd5b81356117c881611d33565b600060208284031215611d8757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611df8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60006101208284031215611e1157600080fd5b50919050565b60006101208284031215611e2a57600080fd5b6117c88383611dfe565b6000806000806101608587031215611e4b57600080fd5b611e558686611dfe565b935061012085013567ffffffffffffffff80821115611e7357600080fd5b818701915087601f830112611e8757600080fd5b813581811115611e9657600080fd5b886020828501011115611ea857600080fd5b9598602092909201975094956101400135945092505050565b60008083601f840112611ed357600080fd5b50813567ffffffffffffffff811115611eeb57600080fd5b6020830191508360208260051b8501011115611f0657600080fd5b9250929050565b60008060008060008060608789031215611f2657600080fd5b863567ffffffffffffffff80821115611f3e57600080fd5b818901915089601f830112611f5257600080fd5b813581811115611f6157600080fd5b8a602061012083028501011115611f7757600080fd5b602092830198509650908801359080821115611f9257600080fd5b611f9e8a838b01611ec1565b90965094506040890135915080821115611fb757600080fd5b50611fc489828a01611ec1565b979a9699509497509295939492505050565b600060208284031215611fe857600080fd5b815180151581146117c857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261205c57600080fd5b83018035915067ffffffffffffffff82111561207757600080fd5b602001915036819003821315611f0657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156120cd576120cd61208c565b500390565b6000602082840312156120e457600080fd5b5051919050565b6000602082840312156120fd57600080fd5b81516117c881611d33565b805165ffffffffffff8116811461211e57600080fd5b919050565b60008060008060008060c0878903121561213c57600080fd5b865161214781611d33565b602088015190965061215881611d33565b604088015190955061216981611d33565b606088015190945061217a81611d33565b925061218860808801612108565b915060a087015190509295509295509295565b600082198211156121ae576121ae61208c565b500190565b600080604083850312156121c657600080fd5b825191506121d660208401612108565b90509250929050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000808585111561223c57600080fd5b8386111561224957600080fd5b5050820193919092039150565b80356020831015610de3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b6000825160005b818110156122b35760208186018101518583015201612299565b818111156122c2576000828501525b50919091019291505056fea26469706673582212206cfa9ee5c0c9e78600b4353963d93432999c234b193d9347ce01a434b75153b864736f6c634300080f0033000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1000000000000000000000000007a2f0a16bd0874ca2e1fffafc2d6b0b876aa8e

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063816fae771161008c5780639a8a0592116100665780639a8a05921461020f578063bf7e214f14610218578063dc9cde9014610238578063ef734c881461024b57600080fd5b8063816fae77146101d457806389ccfe89146101e75780638da5cb5b146101ef57600080fd5b80633644e515116100c85780633644e51514610185578063501724001461019b5780636dfdff1a146101ae5780637a9e5e4b146101c157600080fd5b806313af4035146100ef578063245a7bfc146101045780632dff692d14610155575b600080fd5b6101026100fd366004611d58565b61025e565b005b61012b7f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d181565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b610178610163366004611d75565b60046020526000908152604090205460ff1681565b60405161014c9190611dbd565b61018d610367565b60405190815260200161014c565b6101026101a9366004611e17565b610426565b6101026101bc366004611e34565b610580565b6101026101cf366004611d58565b610626565b61018d6101e2366004611e17565b610783565b6101026108d3565b60005461012b9073ffffffffffffffffffffffffffffffffffffffff1681565b61018d60025481565b60015461012b9073ffffffffffffffffffffffffffffffffffffffff1681565b610102610246366004611f0d565b6109ef565b610102610259366004611e17565b610b45565b61028c336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b6102f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6000600254461461041f5761041a604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f9718f7897be4857a1c4db401bfbda0cdc8360f3aa819b459203ddc8a51bf046d918101919091527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b5060035490565b61043861012082016101008301611d58565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461049c576040517fd269887400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160e0013510156104e0576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e082013560048201526024016102ee565b60006104eb82610783565b9050600260008281526004602052604090205460ff16600281111561051257610512611d8e565b14610549576040517fcc4da24c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600090815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550565b6105ae336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b610614576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102ee565b61062084848484610de9565b50505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061070957506001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201526000357fffffffff0000000000000000000000000000000000000000000000000000000016604482015273ffffffffffffffffffffffffffffffffffffffff9091169063b700961390606401602060405180830381865afa1580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611fd6565b61071257600080fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b600061078d610367565b7fee6d67b4f9cc8f0b2d8f722a450a03cc8283e7395eb38633d51e03342081899d83356107c06040860160208701611d58565b6107d06060870160408801611d58565b6060870135608088013560a089013560c08a013560e08b01356107fb6101208d016101008e01611d58565b60408051602081019b909b528a019890985273ffffffffffffffffffffffffffffffffffffffff96871660608a0152948616608089015260a088019390935260c087019190915260e08601526101008501526101208401521661014082015261016001604051602081830303815290604052805190602001206040516020016108b69291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050919050565b600254460361093e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444f4d41494e5f534550415241544f525f414c52454144595f5550444154454460448201526064016102ee565b466002556109ea604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f9718f7897be4857a1c4db401bfbda0cdc8360f3aa819b459203ddc8a51bf046d918101919091527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b600355565b610a1d336000357fffffffff0000000000000000000000000000000000000000000000000000000016610cd6565b610a83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102ee565b848181141580610a935750808414155b15610aca576040517f84853dcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b3b57610b33888883818110610aea57610aea611ff8565b90506101200201878784818110610b0357610b03611ff8565b9050602002810190610b159190612027565b878786818110610b2757610b27611ff8565b90506020020135610de9565b600101610acd565b5050505050505050565b610b5761012082016101008301611d58565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bbb576040517fd269887400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428160e001351015610bff576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e082013560048201526024016102ee565b6000610c0a82610783565b90506000808281526004602052604090205460ff166002811115610c3057610c30611d8e565b14610c67576040517fcc4da24c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600217905590518281527f5152abf959f6564662358c2e52b702259b78bac5ee7842a0f01937e670efcc7d910160405180910390a15050565b60015460009073ffffffffffffffffffffffffffffffffffffffff168015801590610dba57506040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301523060248301527fffffffff000000000000000000000000000000000000000000000000000000008516604483015282169063b700961390606401602060405180830381865afa158015610d96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dba9190611fd6565b80610ddf575060005473ffffffffffffffffffffffffffffffffffffffff8581169116145b9150505b92915050565b6000610df68585856115c9565b9050428560e001351015610e3c576040517f15deed9500000000000000000000000000000000000000000000000000000000815260e086013560048201526024016102ee565b6040517f27507458000000000000000000000000000000000000000000000000000000008152853560048201527f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d173ffffffffffffffffffffffffffffffffffffffff1690632750745890602401602060405180830381865afa158015610ec7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eeb9190611fd6565b610f24576040517f08c51810000000000000000000000000000000000000000000000000000000008152853560048201526024016102ee565b60008181526004602052604090205460ff166001816002811115610f4a57610f4a611d8e565b03610f84576040517f9396c312000000000000000000000000000000000000000000000000000000008152600481018390526024016102ee565b6002816002811115610f9857610f98611d8e565b03610fd2576040517f1616126a000000000000000000000000000000000000000000000000000000008152600481018390526024016102ee565b8560a0013583111561101d576040517f8776a2030000000000000000000000000000000000000000000000000000000081526004810184905260a087013560248201526044016102ee565b600061102d8460608901356120bb565b600084815260046020526040902080549192506001917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682800217905550600073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d11663c7bf8ca089356110bc60608c0160408d01611d58565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925273ffffffffffffffffffffffffffffffffffffffff166024820152604401602060405180830381865afa15801561112b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114f91906120d2565b90506080880135818311156112555781925080600014611255576040517f946824cd000000000000000000000000000000000000000000000000000000008152893560048201526000907f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d173ffffffffffffffffffffffffffffffffffffffff169063946824cd90602401602060405180830381865afa1580156111f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121b91906120d2565b90506000611243828c608001358d60a001358e6060013561123c91906120bb565b91906117cf565b90506112508583836117cf565b925050505b6040517f52047942000000000000000000000000000000000000000000000000000000008152893560048201526000907f000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d173ffffffffffffffffffffffffffffffffffffffff1690635204794290602401602060405180830381865afa1580156112e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130791906120eb565b6040517facc5570c0000000000000000000000000000000000000000000000000000000081528b35600482015290915060009073ffffffffffffffffffffffffffffffffffffffff83169063acc5570c9060240160c060405180830381865afa158015611378573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139c9190612123565b505093505050506113e48b6101000160208101906113ba9190611d58565b306113c58b8961219b565b73ffffffffffffffffffffffffffffffffffffffff851692919061189b565b60008273ffffffffffffffffffffffffffffffffffffffff16639787d1076040518163ffffffff1660e01b8152600401602060405180830381865afa158015611431573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145591906120eb565b905061147873ffffffffffffffffffffffffffffffffffffffff83168288611a37565b8073ffffffffffffffffffffffffffffffffffffffff16636de5b4cd8d60200160208101906114a79190611d58565b8e60400160208101906114ba9190611d58565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201528e356044820152606481018990526084810187905260a40160408051808303816000875af1158015611540573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156491906121b3565b50611588905073ffffffffffffffffffffffffffffffffffffffff8316338b611ba7565b6040518881527fc0688adab4193f84179a2fda51c33be35f0be04eda978b688bb1a41ce2c7e8469060200160405180910390a1505050505050505050505050565b6000806115de61012086016101008701611d58565b73ffffffffffffffffffffffffffffffffffffffff160361162b576040517fd697e28f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604182146116695782826040517f256d83e50000000000000000000000000000000000000000000000000000000081526004016102ee9291906121df565b600061167485610783565b90506000611685602082868861222c565b61168e91612256565b905060006116a060406020878961222c565b6116a991612256565b90506000868660408181106116c0576116c0611ff8565b604080516000808252602082018084528a9052949092013560f81c908201819052606082018790526080820186905293506001915060a0016020604051602081039080840390855afa15801561171a573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00151915061175890506101208a016101008b01611d58565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146117c05787876040517f256d83e50000000000000000000000000000000000000000000000000000000081526004016102ee9291906121df565b509293505050505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003611826576000841161181b57600080fd5b5082900490506117c8565b80841161183257600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161193a9190612292565b6000604051808303816000865af19150503d8060008114611977576040519150601f19603f3d011682016040523d82523d6000602084013e61197c565b606091505b50915091508180156119a65750805115806119a65750808060200190518101906119a69190611fd6565b80156119c9575060008673ffffffffffffffffffffffffffffffffffffffff163b115b611a2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064016102ee565b505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790529151600092839290871691611ace9190612292565b6000604051808303816000865af19150503d8060008114611b0b576040519150601f19603f3d011682016040523d82523d6000602084013e611b10565b606091505b5091509150818015611b3a575080511580611b3a575080806020019051810190611b3a9190611fd6565b611ba0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c454400000000000000000000000000000000000060448201526064016102ee565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691611c3e9190612292565b6000604051808303816000865af19150503d8060008114611c7b576040519150601f19603f3d011682016040523d82523d6000602084013e611c80565b606091505b5091509150818015611caa575080511580611caa575080806020019051810190611caa9190611fd6565b8015611ccd575060008573ffffffffffffffffffffffffffffffffffffffff163b115b611ba0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c4544000000000000000000000000000000000060448201526064016102ee565b73ffffffffffffffffffffffffffffffffffffffff81168114611d5557600080fd5b50565b600060208284031215611d6a57600080fd5b81356117c881611d33565b600060208284031215611d8757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611df8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60006101208284031215611e1157600080fd5b50919050565b60006101208284031215611e2a57600080fd5b6117c88383611dfe565b6000806000806101608587031215611e4b57600080fd5b611e558686611dfe565b935061012085013567ffffffffffffffff80821115611e7357600080fd5b818701915087601f830112611e8757600080fd5b813581811115611e9657600080fd5b886020828501011115611ea857600080fd5b9598602092909201975094956101400135945092505050565b60008083601f840112611ed357600080fd5b50813567ffffffffffffffff811115611eeb57600080fd5b6020830191508360208260051b8501011115611f0657600080fd5b9250929050565b60008060008060008060608789031215611f2657600080fd5b863567ffffffffffffffff80821115611f3e57600080fd5b818901915089601f830112611f5257600080fd5b813581811115611f6157600080fd5b8a602061012083028501011115611f7757600080fd5b602092830198509650908801359080821115611f9257600080fd5b611f9e8a838b01611ec1565b90965094506040890135915080821115611fb757600080fd5b50611fc489828a01611ec1565b979a9699509497509295939492505050565b600060208284031215611fe857600080fd5b815180151581146117c857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261205c57600080fd5b83018035915067ffffffffffffffff82111561207757600080fd5b602001915036819003821315611f0657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156120cd576120cd61208c565b500390565b6000602082840312156120e457600080fd5b5051919050565b6000602082840312156120fd57600080fd5b81516117c881611d33565b805165ffffffffffff8116811461211e57600080fd5b919050565b60008060008060008060c0878903121561213c57600080fd5b865161214781611d33565b602088015190965061215881611d33565b604088015190955061216981611d33565b606088015190945061217a81611d33565b925061218860808801612108565b915060a087015190509295509295509295565b600082198211156121ae576121ae61208c565b500190565b600080604083850312156121c657600080fd5b825191506121d660208401612108565b90509250929050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000808585111561223c57600080fd5b8386111561224957600080fd5b5050820193919092039150565b80356020831015610de3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b6000825160005b818110156122b35760208186018101518583015201612299565b818111156122c2576000828501525b50919091019291505056fea26469706673582212206cfa9ee5c0c9e78600b4353963d93432999c234b193d9347ce01a434b75153b864736f6c634300080f0033

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

000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1000000000000000000000000007a2f0a16bd0874ca2e1fffafc2d6b0b876aa8e

-----Decoded View---------------
Arg [0] : aggregator_ (address): 0x007A66A2a13415DB3613C1a4dd1C942A285902d1
Arg [1] : authority_ (address): 0x007A2F0A16bd0874CA2e1FFfAfc2d6B0b876aA8E

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000007a66a2a13415db3613c1a4dd1c942a285902d1
Arg [1] : 000000000000000000000000007a2f0a16bd0874ca2e1fffafc2d6b0b876aa8e


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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