ETH Price: $2,415.94 (-2.61%)

Contract

0x9CC43eA3688a1D793155aA33DF1C42Af47C393Ed
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Redeem205227162024-08-13 22:33:4755 days ago1723588427IN
0x9CC43eA3...f47C393Ed
0 ETH0.000094671.40745681
Redeem204732832024-08-07 1:02:4762 days ago1722992567IN
0x9CC43eA3...f47C393Ed
0 ETH0.000100722.00829909
Redeem202303682024-07-04 3:08:5996 days ago1720062539IN
0x9CC43eA3...f47C393Ed
0 ETH0.000319724.75297034
Redeem202226162024-07-03 1:10:5997 days ago1719969059IN
0x9CC43eA3...f47C393Ed
0 ETH0.00017312.57333406
Redeem200613582024-06-10 12:13:47119 days ago1718021627IN
0x9CC43eA3...f47C393Ed
0 ETH0.000428878.54869521
Redeem199943612024-06-01 3:43:47129 days ago1717213427IN
0x9CC43eA3...f47C393Ed
0 ETH0.000483927.19402615
Redeem198998522024-05-18 22:36:47142 days ago1716071807IN
0x9CC43eA3...f47C393Ed
0 ETH0.00018932.81468335
Redeem198848362024-05-16 20:10:59144 days ago1715890259IN
0x9CC43eA3...f47C393Ed
0 ETH0.0002374.72416348
Redeem198749532024-05-15 11:02:23145 days ago1715770943IN
0x9CC43eA3...f47C393Ed
0 ETH0.000333564.95877175
Redeem198476942024-05-11 15:30:47149 days ago1715441447IN
0x9CC43eA3...f47C393Ed
0 ETH0.000311466.20701221
Redeem198085092024-05-06 3:57:47155 days ago1714967867IN
0x9CC43eA3...f47C393Ed
0 ETH0.000224684.47759237
Redeem197981362024-05-04 17:08:59156 days ago1714842539IN
0x9CC43eA3...f47C393Ed
0 ETH0.000311716.21191155
Redeem197892522024-05-03 11:20:35157 days ago1714735235IN
0x9CC43eA3...f47C393Ed
0 ETH0.000272045.42129102
Redeem197808222024-05-02 7:03:23159 days ago1714633403IN
0x9CC43eA3...f47C393Ed
0 ETH0.000450926.70342693
Redeem197768952024-05-01 17:52:47159 days ago1714585967IN
0x9CC43eA3...f47C393Ed
0 ETH0.000440678.78186457
Redeem197711222024-04-30 22:32:11160 days ago1714516331IN
0x9CC43eA3...f47C393Ed
0 ETH0.000474119.45052929
Redeem197705352024-04-30 20:33:23160 days ago1714509203IN
0x9CC43eA3...f47C393Ed
0 ETH0.0005809911.58097012
Redeem197554432024-04-28 17:55:59162 days ago1714326959IN
0x9CC43eA3...f47C393Ed
0 ETH0.000438128.73318215
Redeem197511302024-04-28 3:27:59163 days ago1714274879IN
0x9CC43eA3...f47C393Ed
0 ETH0.000292875.83639702
Redeem197489112024-04-27 20:00:35163 days ago1714248035IN
0x9CC43eA3...f47C393Ed
0 ETH0.000362455.38817173
Redeem197444872024-04-27 5:07:47164 days ago1714194467IN
0x9CC43eA3...f47C393Ed
0 ETH0.000280935.59996085
Redeem197438182024-04-27 2:52:47164 days ago1714186367IN
0x9CC43eA3...f47C393Ed
0 ETH0.000282665.63440707
Redeem197367342024-04-26 3:03:47165 days ago1714100627IN
0x9CC43eA3...f47C393Ed
0 ETH0.000264835.27896223
Redeem197303192024-04-25 5:33:23166 days ago1714023203IN
0x9CC43eA3...f47C393Ed
0 ETH0.0003677.3155745
Redeem197301622024-04-25 5:01:59166 days ago1714021319IN
0x9CC43eA3...f47C393Ed
0 ETH0.000388365.77340903
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PublicPreListBondDepository

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 2000 runs

Other Settings:
default evmVersion, GNU AGPLv3 license
File 1 of 19 : PublicPreListBondDepository.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;

import "../Types/NoteKeeper.sol";
import "../Types/Signed.sol";
import "../Types/PriceConsumerV3.sol";

import "../Libraries/SafeERC20.sol";

import "../Interfaces/IERC20Metadata.sol";
import "../Interfaces/IWhitelistBondDepository.sol";

/**
 * @title Theopetra Public Pre-List Bond Depository
 * @notice Based off of WhitelistTheopetraBondDepository, with the call to `verifySignature` removed,
 *         as well as the function `setWethHelper` and state variable `wethHelper` removed
 */

contract PublicPreListBondDepository is IWhitelistBondDepository, NoteKeeper, Signed, PriceConsumerV3 {
    /* ======== DEPENDENCIES ======== */

    using SafeERC20 for IERC20;

    /* ======== EVENTS ======== */

    event CreateMarket(
        uint256 indexed id,
        address indexed baseToken,
        address indexed quoteToken,
        uint256 fixedBondPrice
    );
    event CloseMarket(uint256 indexed id);
    event Bond(uint256 indexed id, uint256 amount, uint256 price);

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

    // Storage
    Market[] public markets; // persistent market data
    Terms[] public terms; // deposit construction data
    Metadata[] public metadata; // extraneous market data

    // Queries
    mapping(address => uint256[]) public marketsForQuote; // market IDs for quote token

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

    constructor(
        ITheopetraAuthority _authority,
        IERC20 _theo,
        IStakedTHEOToken _stheo,
        IStaking _staking,
        ITreasury _treasury
    ) NoteKeeper(_authority, _theo, _stheo, _staking, _treasury) {
        // save gas for users by bulk approving stake() transactions
        _theo.approve(address(_staking), 1e45);
    }

    /* ======== DEPOSIT ======== */

    /**
     * @notice             deposit quote tokens in exchange for a bond from a specified market
     * @param _id          the ID of the market
     * @param _amount      the amount of quote token to spend
     * @param _maxPrice    the maximum price at which to buy
     * @param _user        the recipient of the payout
     * @param _referral    the front end operator address
     * @return depositInfo DepositInfo
     */
    function deposit(
        uint256 _id,
        uint256 _amount,
        uint256 _maxPrice,
        address _user,
        address _referral,
        bytes calldata signature
    ) external override returns (DepositInfo memory depositInfo) {
        Market storage market = markets[_id];
        Terms memory term = terms[_id];
        uint48 currentTime = uint48(block.timestamp);

        // Markets end at a defined timestamp
        // |-------------------------------------| t
        require(currentTime < term.conclusion, "Depository: market concluded");

        // Get the price of THEO in quote token terms
        // i.e. the number of quote tokens per THEO
        // With 9 decimal places
        uint256 price = calculatePrice(_id);

        // Users input a maximum price, which protects them from price changes after
        // entering the mempool. max price is a slippage mitigation measure
        require(price <= _maxPrice, "Depository: more than max price");

        /**
         * payout for the deposit = amount / price
         *
         * where
         * payout = THEO out, in THEO decimals (9)
         * amount = quote tokens in
         * price = quote tokens per THEO, in THEO decimals (9)
         *
         * 1e18 = THEO decimals (9) + price decimals (9)
         */
        depositInfo.payout_ = ((_amount * 1e18) / price) / (10**metadata[_id].quoteDecimals);

        /*
         * each market is initialized with a capacity
         *
         * this is either the number of THEO that the market can sell
         * (if capacity in quote is false),
         *
         * or the number of quote tokens that the market can buy
         * (if capacity in quote is true)
         */

        require(
            market.capacity >= (market.capacityInQuote ? _amount : depositInfo.payout_),
            "Depository: capacity exceeded"
        );

        market.capacity -= market.capacityInQuote ? _amount : depositInfo.payout_;

        if (market.capacity == 0) {
            emit CloseMarket(_id);
        }

        /**
         * bonds mature with a cliff at a set timestamp
         * prior to the expiry timestamp, no payout tokens are accessible to the user
         * after the expiry timestamp, the entire payout can be redeemed
         *
         * there are two types of bonds: fixed-term and fixed-expiration
         *
         * fixed-term bonds mature in a set amount of time from deposit
         * i.e. term = 1 week. when alice deposits on day 1, her bond
         * expires on day 8. when bob deposits on day 2, his bond expires day 9.
         *
         * fixed-expiration bonds mature at a set timestamp
         * i.e. expiration = day 10. when alice deposits on day 1, her term
         * is 9 days. when bob deposits on day 2, his term is 8 days.
         */
        depositInfo.expiry_ = term.fixedTerm ? term.vesting + currentTime : term.vesting;

        // markets keep track of how many quote tokens have been
        // purchased, and how much THEO has been sold
        market.purchased += _amount;
        market.sold += uint64(depositInfo.payout_);

        emit Bond(_id, _amount, price);

        /**
         * user data is stored as Notes. these are isolated array entries
         * storing the amount due, the time created, the time when payout
         * is redeemable, the time when payout was redeemed, and the ID
         * of the market deposited into
         */
        depositInfo.index_ = addNote(
            _user,
            depositInfo.payout_,
            uint48(depositInfo.expiry_),
            uint48(_id),
            _referral,
            0,
            false
        );

        // transfer payment to treasury
        market.quoteToken.safeTransferFrom(msg.sender, address(treasury), _amount);
    }

    /* ======== CREATE ======== */

    /**
     * @notice             creates a new market type
     * @dev                current price should be in 9 decimals.
     * @param _quoteToken  token used to deposit
     * @param _market      [capacity (in THEO or quote), fixed bond price (9 decimals) USD per THEO]
     * @param _booleans    [capacity in quote, fixed term]
     * @param _terms       [vesting length (if fixed term) or vested timestamp, conclusion timestamp]
     * @param _priceFeed   address of the price consumer, to return the USD value for the quote token when deposits are made
     * @return id_         ID of new bond market
     */
    function create(
        IERC20 _quoteToken,
        address _priceFeed,
        uint256[2] memory _market,
        bool[2] memory _booleans,
        uint256[2] memory _terms
    ) external override onlyPolicy returns (uint256 id_) {
        // the decimal count of the quote token
        uint256 decimals = IERC20Metadata(address(_quoteToken)).decimals();

        // depositing into, or getting info for, the created market uses this ID
        id_ = markets.length;

        markets.push(
            Market({
                quoteToken: _quoteToken,
                priceFeed: _priceFeed,
                capacityInQuote: _booleans[0],
                capacity: _market[0],
                purchased: 0,
                sold: 0,
                usdPricePerTHEO: _market[1]
            })
        );

        terms.push(Terms({ fixedTerm: _booleans[1], vesting: uint48(_terms[0]), conclusion: uint48(_terms[1]) }));

        metadata.push(Metadata({ quoteDecimals: uint8(decimals) }));

        marketsForQuote[address(_quoteToken)].push(id_);

        emit CreateMarket(id_, address(theo), address(_quoteToken), _market[1]);
    }

    /**
     * @notice             disable existing market
     * @param _id          ID of market to close
     */
    function close(uint256 _id) external override onlyPolicy {
        terms[_id].conclusion = uint48(block.timestamp);
        markets[_id].capacity = 0;
        emit CloseMarket(_id);
    }

    /* ======== EXTERNAL VIEW ======== */

    /**
     * @notice             payout due for amount of quote tokens
     * @param _amount      amount of quote tokens to spend
     * @param _id          ID of market
     * @return             amount of THEO to be paid in THEO decimals
     *
     * @dev 1e18 = theo decimals (9) + fixed bond price decimals (9)
     */
    function payoutFor(uint256 _amount, uint256 _id) external view override returns (uint256) {
        Metadata memory meta = metadata[_id];
        return (_amount * 1e18) / calculatePrice(_id) / 10**meta.quoteDecimals;
    }

    /**
     * @notice             is a given market accepting deposits
     * @param _id          ID of market
     */
    function isLive(uint256 _id) public view override returns (bool) {
        return (markets[_id].capacity != 0 && terms[_id].conclusion > block.timestamp);
    }

    /**
     * @notice returns an array of all active market IDs
     */
    function liveMarkets() external view override returns (uint256[] memory) {
        uint256 num;
        for (uint256 i = 0; i < markets.length; i++) {
            if (isLive(i)) num++;
        }

        uint256[] memory ids = new uint256[](num);
        uint256 nonce;
        for (uint256 i = 0; i < markets.length; i++) {
            if (isLive(i)) {
                ids[nonce] = i;
                nonce++;
            }
        }
        return ids;
    }

    /**
     * @notice             returns an array of all active market IDs for a given quote token
     * @param _token       quote token to check for
     */
    function liveMarketsFor(address _token) external view override returns (uint256[] memory) {
        uint256[] memory mkts = marketsForQuote[_token];
        uint256 num;

        for (uint256 i = 0; i < mkts.length; i++) {
            if (isLive(mkts[i])) num++;
        }

        uint256[] memory ids = new uint256[](num);
        uint256 nonce;

        for (uint256 i = 0; i < mkts.length; i++) {
            if (isLive(mkts[i])) {
                ids[nonce] = mkts[i];
                nonce++;
            }
        }
        return ids;
    }

    /**
     * @notice returns an array of market IDs for historical analysis
     */
    function getMarkets() external view override returns (uint256[] memory) {
        uint256[] memory ids = new uint256[](markets.length);
        for (uint256 i = 0; i < markets.length; i++) {
                ids[i] = i;
        }
        return ids;
    }

    /**
     * @notice             returns an array of all market IDs for a given quote token
     * @param _token       quote token to check for
     */
    function getMarketsFor(address _token) external view override returns (uint256[] memory) {
        uint256[] memory mkts = marketsForQuote[_token];
        uint256[] memory ids = new uint256[](mkts.length);

        for (uint256 i = 0; i < mkts.length; i++) {
            ids[i] = mkts[i];
        }
        return ids;
    }

    /**
     * @notice                  calculate the price of THEO in quote token terms; i.e. the number of quote tokens per THEO
     * @dev                     get the latest price for the market's quote token in USD
     *                          (`priceConsumerPrice`, with decimals `priceConsumerDecimals`)
     *                          then `scalePrice` to scale the fixed bond price to THEO decimals when calculating `price`.
     *                          finally, calculate `price` as quote tokens per THEO, in THEO decimals (9)
     * @param _id               market ID
     * @return                  uint256 price of THEO in quote token terms, in THEO decimals (9)
     */
    function calculatePrice(uint256 _id) public view override returns (uint256) {
        (int256 priceConsumerPrice, uint8 priceConsumerDecimals) = getLatestPrice(markets[_id].priceFeed);

        int256 scaledPrice = scalePrice(int256(markets[_id].usdPricePerTHEO), 9, 9 + priceConsumerDecimals);

        uint256 price = uint256(scaledPrice / priceConsumerPrice);
        return price;
    }

    /* ======== INTERNAL PURE ======== */

    /**
     * @param _price            fixed bond price (USD per THEO), 9 decimals
     * @param _priceDecimals    decimals (9) used for the fixed bond price
     * @param _decimals         sum of decimals for THEO token (9) + decimals for the price feed
     */
    function scalePrice(
        int256 _price,
        uint8 _priceDecimals,
        uint8 _decimals
    ) internal pure returns (int256) {
        if (_priceDecimals < _decimals) {
            return _price * int256(10**uint256(_decimals - _priceDecimals));
        } else if (_priceDecimals > _decimals) {
            return _price / int256(10**uint256(_priceDecimals - _decimals));
        }
        return _price;
    }
}

File 2 of 19 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );
}

File 3 of 19 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

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

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

File 4 of 19 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (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) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        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.
            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 if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } 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 5 of 19 : IBondCalculator.sol
// SPDX-License-Identifier: AGPL-1.0

pragma solidity >=0.7.5 <=0.8.10;

interface IBondCalculator {
    function valuation(address tokenIn, uint256 amount_) external view returns (uint256 amountOut);
}

File 6 of 19 : IERC20.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

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

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 7 of 19 : IERC20Metadata.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

import "./IERC20.sol";

interface IERC20Metadata is IERC20 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

File 8 of 19 : INoteKeeper.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.7.5;

interface INoteKeeper {
    /**
     * @notice  Info for market note
     * @dev     Note::payout is sTHEO remaining to be paid
     *          Note::created is the time the Note was created
     *          Note::matured is the timestamp when the Note is redeemable
     *          Note::redeemed is time market was redeemed
     *          Note::marketID is market ID of deposit. uint48 to avoid adding a slot.
     */
    struct Note {
        uint256 payout;
        uint48 created;
        uint48 matured;
        uint48 redeemed;
        uint48 marketID;
        uint48 discount;
        bool autoStake;
    }

    function redeem(address _user, uint256[] memory _indexes) external returns (uint256);

    function redeemAll(address _user) external returns (uint256);

    function pushNote(address to, uint256 index) external;

    function pullNote(address from, uint256 index) external returns (uint256 newIndex_);

    function indexesFor(address _user) external view returns (uint256[] memory);

    function pendingFor(address _user, uint256 _index)
        external
        view
        returns (
            uint256 payout_,
            uint48 created_,
            uint48 expiry_,
            uint48 timeRemaining_,
            bool matured_,
            uint48 discount_
        );
}

File 9 of 19 : IStakedTHEOToken.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

import "./IERC20.sol";

interface IStakedTHEOToken is IERC20 {
    function rebase(uint256 theoProfit_, uint256 epoch_) external returns (uint256);

    function circulatingSupply() external view returns (uint256);

    function balanceOf(address who) external view override returns (uint256);

    function gonsForBalance(uint256 amount) external view returns (uint256);

    function balanceForGons(uint256 gons) external view returns (uint256);

    function index() external view returns (uint256);
}

File 10 of 19 : IStaking.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

interface IStaking {
    function stake(
        address _to,
        uint256 _amount,
        bool _claim
    ) external returns (uint256, uint256 _index);

    function claim(address _recipient, bool _rebasing) external returns (uint256);

    function forfeit(uint256 _index) external;

    function toggleLock() external;

    function unstake(
        address _to,
        uint256 _amount,
        bool _trigger,
        bool _rebasing
    ) external returns (uint256);

    function wrap(address _to, uint256 _amount) external returns (uint256 gBalance_);

    function unwrap(address _to, uint256 _amount) external returns (uint256 sBalance_);

    function rebase() external;

    function index() external view returns (uint256);

    function contractBalance() external view returns (uint256);

    function totalStaked() external view returns (uint256);

    function supplyInWarmup() external view returns (uint256);

    function indexesFor(address _user) external view returns (uint256[] memory);

    function claimAll(address _recipient) external returns (uint256);

    function pushClaim(address _to, uint256 _index) external;

    function pullClaim(address _from, uint256 _index) external returns (uint256 newIndex_);

    function pushClaimForBond(address _to, uint256 _index) external returns (uint256 newIndex_);

    function basis() external view returns (address);
}

File 11 of 19 : ITheopetraAuthority.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

interface ITheopetraAuthority {
    /* ========== EVENTS ========== */

    event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event ManagerPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
    event SignerPushed(address indexed from, address indexed to, bool _effectiveImmediately);

    event GovernorPulled(address indexed from, address indexed to);
    event GuardianPulled(address indexed from, address indexed to);
    event PolicyPulled(address indexed from, address indexed to);
    event ManagerPulled(address indexed from, address indexed to);
    event VaultPulled(address indexed from, address indexed to);
    event SignerPulled(address indexed from, address indexed to);

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

    function governor() external view returns (address);

    function guardian() external view returns (address);

    function policy() external view returns (address);

    function manager() external view returns (address);

    function vault() external view returns (address);

    function whitelistSigner() external view returns (address);
}

File 12 of 19 : ITreasury.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

import "./IBondCalculator.sol";

interface ITreasury {
    function deposit(
        uint256 _amount,
        address _token,
        uint256 _profit
    ) external returns (uint256);

    function withdraw(uint256 _amount, address _token) external;

    function tokenValue(address _token, uint256 _amount) external view returns (uint256 value_);

    function mint(address _recipient, uint256 _amount) external;

    function manage(address _token, uint256 _amount) external;

    function incurDebt(uint256 amount_, address token_) external;

    function repayDebtWithReserve(uint256 amount_, address token_) external;

    function tokenPerformanceUpdate() external;

    function baseSupply() external view returns (uint256);

    function deltaTokenPrice() external view returns (int256);

    function deltaTreasuryYield() external view returns (int256);

    function getTheoBondingCalculator() external view returns (IBondCalculator);

    function setTheoBondingCalculator(address _theoBondingCalculator) external;
}

File 13 of 19 : IWhitelistBondDepository.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.7.5;

import "./IERC20.sol";

interface IWhitelistBondDepository {
    /**
     * @notice      Info about each type of market
     * @dev         Market::capacity is capacity remaining
     *              Market::quoteToken is token to accept as payment
     *              Market::priceFeed is address of the price consumer, to return the USD value for the quote token when deposits are made
     *              Market::capacityInQuote is in payment token (true) or in THEO (false, default)
     *              Market::sold is base tokens out
     *              Market::purchased quote tokens in
     *              Market::usdPricePerTHEO is 9 decimal USD value for each THEO bond
     */
    struct Market {
        uint256 capacity;
        IERC20 quoteToken;
        address priceFeed;
        bool capacityInQuote;
        uint64 sold;
        uint256 purchased;
        uint256 usdPricePerTHEO;
    }

    /**
     * @notice      Info for creating new markets
     * @dev         Terms::fixedTerm is fixed term or fixed expiration
     *              Terms::vesting is length of time from deposit to maturity if fixed-term
     *              Terms::conclusion is timestamp when market no longer offered (doubles as time when market matures if fixed-expiry)
     */
    struct Terms {
        bool fixedTerm;
        uint48 vesting;
        uint48 conclusion;
    }

    /**
     * @notice      Additional info about market
     * @dev         Metadata::quoteDecimals is decimals of quote token
     */
    struct Metadata {
        uint8 quoteDecimals;
    }

    struct DepositInfo {
        uint256 payout_;
        uint256 expiry_;
        uint256 index_;
    }

    /**
     * @notice deposit market
     * @param _bid uint256
     * @param _amount uint256
     * @param _maxPrice uint256
     * @param _user address
     * @param _referral address
     * @param signature bytes
     * @return depositInfo DepositInfo
     */
    function deposit(
        uint256 _bid,
        uint256 _amount,
        uint256 _maxPrice,
        address _user,
        address _referral,
        bytes calldata signature
    ) external returns (DepositInfo memory depositInfo);

    /**
     * @notice create market
     * @param _quoteToken IERC20 is the token used to deposit
     * @param _priceFeed address is address of the price consumer, to return the USD value for the quote token when deposits are made
     * @param _market uint256[2] is [capacity, fixed bond price (9 decimals) USD per THEO]
     * @param _booleans bool[2] is [capacity in quote, fixed term]
     * @param _terms uint256[2] is [vesting, conclusion]
     * @return id_ uint256 is ID of the market
     */
    function create(
        IERC20 _quoteToken,
        address _priceFeed,
        uint256[2] memory _market,
        bool[2] memory _booleans,
        uint256[2] memory _terms
    ) external returns (uint256 id_);

    function close(uint256 _id) external;

    function isLive(uint256 _bid) external view returns (bool);

    function liveMarkets() external view returns (uint256[] memory);

    function liveMarketsFor(address _quoteToken) external view returns (uint256[] memory);

    function getMarkets() external view returns (uint256[] memory);

    function getMarketsFor(address _quoteToken) external view returns (uint256[] memory);

    function calculatePrice(uint256 _bid) external view returns (uint256);

    function payoutFor(uint256 _amount, uint256 _bid) external view returns (uint256);
}

File 14 of 19 : SafeERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.7.5;

import { IERC20 } from "../Interfaces/IERC20.sol";

/// @notice Safe IERC20 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)
/// Taken from Solmate
library SafeERC20 {
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)
        );

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

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

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

    function safeApprove(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(IERC20.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");
    }
}

File 15 of 19 : FrontEndRewarder.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.10;

import "../Types/TheopetraAccessControlled.sol";
import "../Interfaces/IERC20.sol";

abstract contract FrontEndRewarder is TheopetraAccessControlled {
    /* ========= STATE VARIABLES ========== */

    uint256 public daoReward; // % reward for dao (3 decimals: 100 = 1%)
    uint256 public refReward; // % reward for referrer (3 decimals: 100 = 1%)
    mapping(address => uint256) public rewards; // front end operator rewards
    mapping(address => bool) public whitelisted; // whitelisted status for operators

    IERC20 internal immutable theo; // reward token

    event SetRewards(uint256 toRef, uint256 toDao);
    constructor(ITheopetraAuthority _authority, IERC20 _theo) TheopetraAccessControlled(_authority) {
        theo = _theo;
    }

    /* ========= EXTERNAL FUNCTIONS ========== */

    // pay reward to front end operator
    function getReward() external {
        uint256 reward = rewards[msg.sender];

        rewards[msg.sender] = 0;
        theo.transfer(msg.sender, reward);
    }

    /* ========= INTERNAL ========== */

    /**
     * @notice add new market payout to user data
     */
    function _giveRewards(uint256 _payout, address _referral) internal returns (uint256) {
        // first we calculate rewards paid to the DAO and to the front end operator (referrer)
        uint256 toDAO = (_payout * daoReward) / 1e4;
        uint256 toRef = (_payout * refReward) / 1e4;

        // and store them in our rewards mapping
        if (whitelisted[_referral]) {
            rewards[_referral] += toRef;
            rewards[authority.guardian()] += toDAO;
        } else {
            // the DAO receives both rewards if referrer is not whitelisted
            rewards[authority.guardian()] += toDAO + toRef;
        }
        return toDAO + toRef;
    }

    /**
     * @notice set rewards for front end operators and DAO
     */
    function setRewards(uint256 _toFrontEnd, uint256 _toDAO) external onlyGovernor {
        refReward = _toFrontEnd;
        daoReward = _toDAO;

        emit SetRewards(_toFrontEnd, _toDAO);
    }

    /**
     * @notice add or remove addresses from the reward whitelist
     */
    function whitelist(address _operator) external onlyPolicy {
        whitelisted[_operator] = !whitelisted[_operator];
    }
}

File 16 of 19 : NoteKeeper.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.10;

import "./FrontEndRewarder.sol";

import "../Interfaces/IStakedTHEOToken.sol";
import "../Interfaces/IStaking.sol";
import "../Interfaces/ITreasury.sol";
import "../Interfaces/INoteKeeper.sol";

abstract contract NoteKeeper is INoteKeeper, FrontEndRewarder {
    mapping(address => Note[]) public notes; // user deposit data
    mapping(address => mapping(uint256 => address)) private noteTransfers; // change note ownership
    mapping(address => mapping(uint256 => uint256)) private noteForClaim; // index of staking claim for a user's note

    event TreasuryUpdated(address addr);
    event PushNote(address from, address to, uint256 noteId);
    event PullNote(address from, address to, uint256 noteId);

    IStakedTHEOToken internal immutable sTHEO;
    IStaking internal immutable staking;
    ITreasury internal treasury;

    constructor(
        ITheopetraAuthority _authority,
        IERC20 _theo,
        IStakedTHEOToken _stheo,
        IStaking _staking,
        ITreasury _treasury
    ) FrontEndRewarder(_authority, _theo) {
        sTHEO = _stheo;
        staking = _staking;
        treasury = _treasury;
    }

    // if treasury address changes on authority, update it
    function updateTreasury() external {
        require(
            msg.sender == authority.governor() ||
                msg.sender == authority.guardian() ||
                msg.sender == authority.policy(),
            "Only authorized"
        );
        address treasuryAddress = authority.vault();
        treasury = ITreasury(treasuryAddress);
        emit TreasuryUpdated(treasuryAddress);
    }

    /* ========== ADD ========== */

    /**
     * @notice             adds a new Note for a user, stores the front end & DAO rewards, and mints & stakes payout & rewards
     * @param _user        the user that owns the Note
     * @param _payout      the amount of THEO due to the user
     * @param _expiry      the timestamp when the Note is redeemable
     * @param _marketID    the ID of the market deposited into
     * @param _discount    the discount on the bond (that is, the bond rate, variable). This is a proportion (that is, a percentage in its decimal form), with 9 decimals
     * @return index_      the index of the Note in the user's array
     */
    function addNote(
        address _user,
        uint256 _payout,
        uint48 _expiry,
        uint48 _marketID,
        address _referral,
        uint48 _discount,
        bool _autoStake
    ) internal returns (uint256 index_) {
        // the index of the note is the next in the user's array
        index_ = notes[_user].length;

        // the new note is pushed to the user's array
        notes[_user].push(
            Note({
                payout: _payout,
                created: uint48(block.timestamp),
                matured: _expiry,
                redeemed: 0,
                marketID: _marketID,
                discount: _discount,
                autoStake: _autoStake
            })
        );

        // front end operators can earn rewards by referring users
        uint256 rewards = _giveRewards(_payout, _referral);

        // mint and stake payout
        treasury.mint(address(this), _payout + rewards);

        if (_autoStake) {
            // note that only the payout gets staked (front end rewards are in THEO)
            // Get index for the claim to approve for pushing
            (, uint256 claimIndex) = staking.stake(address(this), _payout, true);
            // approve the user to transfer the staking claim
            staking.pushClaim(_user, claimIndex);

            // Map the index of the user's note to the claimIndex
            noteForClaim[_user][index_] = claimIndex;
        }
    }

    /* ========== REDEEM ========== */

    /**
     * @notice             redeem notes for user
     * @dev                adapted from Olympus V2. Olympus V2 either sends payout as gOHM
     *                     or calls an `unwrap` function on the staking contract
     *                     to convert the payout from gOHM into sOHM and then send as sOHM.
     *                     This current contract sends payout as sTHEO.
     * @param _user        the user to redeem for
     * @param _indexes     the note indexes to redeem
     * @return payout_     sum of payout sent, in sTHEO
     */
    function redeem(address _user, uint256[] memory _indexes) public override returns (uint256 payout_) {
        uint48 time = uint48(block.timestamp);
        uint256 sTheoPayout = 0;
        uint256 theoPayout = 0;

        for (uint256 i = 0; i < _indexes.length; i++) {
            (uint256 pay, , , , bool matured, ) = pendingFor(_user, _indexes[i]);

            if (matured) {
                notes[_user][_indexes[i]].redeemed = time; // mark as redeemed
                payout_ += pay;
                if (notes[_user][_indexes[i]].autoStake) {
                    uint256 _claimIndex = noteForClaim[_user][_indexes[i]];
                    staking.pushClaimForBond(_user, _claimIndex);
                    sTheoPayout += pay;
                } else {
                    theoPayout += pay;
                }
            }
        }
        if (theoPayout > 0) theo.transfer(_user, theoPayout);
        if (sTheoPayout > 0) sTHEO.transfer(_user, sTheoPayout);
    }

    /**
     * @notice             redeem all redeemable markets for user
     * @dev                if possible, query indexesFor() off-chain and input in redeem() to save gas
     * @param _user        user to redeem all notes for
     * @return             sum of payout sent, in sTHEO
     */
    function redeemAll(address _user) external override returns (uint256) {
        return redeem(_user, indexesFor(_user));
    }

    /* ========== TRANSFER ========== */

    /**
     * @notice             approve an address to transfer a note
     * @param _to          address to approve note transfer for
     * @param _index       index of note to approve transfer for
     */
    function pushNote(address _to, uint256 _index) external override {
        require(notes[msg.sender][_index].created != 0, "Depository: note not found");
        noteTransfers[msg.sender][_index] = _to;

        emit PushNote(msg.sender, _to, _index);
    }

    /**
     * @notice             transfer a note that has been approved by an address
     * @dev                if the note being pulled is autostaked then update noteForClaim as follows:
     *                     get the relevant `claimIndex` associated with the note that is being pulled.
     *                     Then add the claimIndex to the recipient's noteForClaim.
     *                     After updating noteForClaim, the staking claim is pushed to the recipient, in order to
     *                     update `claimTransfers` in the Staking contract and thereby change claim ownership (from the note's pusher to the note's recipient)
     * @param _from        the address that approved the note transfer
     * @param _index       the index of the note to transfer (in the sender's array)
     */
    function pullNote(address _from, uint256 _index) external override returns (uint256 newIndex_) {
        require(noteTransfers[_from][_index] == msg.sender, "Depository: transfer not found");
        require(notes[_from][_index].redeemed == 0, "Depository: note redeemed");

        newIndex_ = notes[msg.sender].length;

        if (notes[_from][_index].autoStake) {
            uint256 claimIndex = noteForClaim[_from][_index];
            noteForClaim[msg.sender][newIndex_] = claimIndex;
            staking.pushClaim(msg.sender, claimIndex);
        }
        notes[msg.sender].push(notes[_from][_index]);

        delete notes[_from][_index];
        emit PullNote(_from, msg.sender, _index);
    }

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

    // Note info

    /**
     * @notice             all pending notes for user
     * @param _user        the user to query notes for
     * @return             the pending notes for the user
     */
    function indexesFor(address _user) public view override returns (uint256[] memory) {
        Note[] memory info = notes[_user];

        uint256 length;
        for (uint256 i = 0; i < info.length; i++) {
            if (info[i].redeemed == 0 && info[i].payout != 0) length++;
        }

        uint256[] memory indexes = new uint256[](length);
        uint256 position;

        for (uint256 i = 0; i < info.length; i++) {
            if (info[i].redeemed == 0 && info[i].payout != 0) {
                indexes[position] = i;
                position++;
            }
        }

        return indexes;
    }

    /**
     * @notice                  calculate amount available for claim for a single note
     * @param _user             the user that the note belongs to
     * @param _index            the index of the note in the user's array
     * @return payout_          the payout due, in sTHEO
     * @return created_         the time the note was created
     * @return expiry_          the time the note is redeemable
     * @return timeRemaining_   the time remaining until the note is matured
     * @return matured_         if the payout can be redeemed
     */
    function pendingFor(address _user, uint256 _index)
        public
        view
        override
        returns (
            uint256 payout_,
            uint48 created_,
            uint48 expiry_,
            uint48 timeRemaining_,
            bool matured_,
            uint48 discount_
        )
    {
        Note memory note = notes[_user][_index];

        payout_ = note.payout;
        created_ = note.created;
        expiry_ = note.matured;
        timeRemaining_ = note.matured > block.timestamp ? uint48(note.matured - block.timestamp) : 0;
        matured_ = note.redeemed == 0 && note.matured <= block.timestamp && note.payout != 0;
        discount_ = note.discount;
    }

    function getNotesCount(address _user) external view returns (uint256) {
        return notes[_user].length;
    }
}

File 17 of 19 : PriceConsumerV3.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.9;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract PriceConsumerV3 {
    /**
     * Returns the latest price
     */
    function getLatestPrice(address priceFeedAddress) public view returns (int256, uint8) {
        (
            uint80 roundID,
            int256 price,
            uint256 startedAt,
            uint256 timeStamp,
            uint80 answeredInRound
        ) = AggregatorV3Interface(priceFeedAddress).latestRoundData();

        uint8 decimals = AggregatorV3Interface(priceFeedAddress).decimals();

        return (price, decimals);
    }
}

File 18 of 19 : Signed.sol
// SPDX-License-Identifier: BSD-3

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import "./TheopetraAccessControlled.sol";

abstract contract Signed is TheopetraAccessControlled {
    using Strings for uint256;
    using ECDSA for bytes32;

    string private _secret;

    event SetSecret(string secret);

    function setSecret(string calldata secret) external onlyGovernor {
        _secret = secret;
        emit SetSecret(secret);
    }

    function createHash(string memory data) internal view returns (bytes32) {
        return keccak256(abi.encodePacked(address(this), msg.sender, data, _secret));
    }

    function getSigner(bytes32 hash, bytes memory signature) internal pure returns (address) {
        return hash.toEthSignedMessageHash().recover(signature);
    }

    function isAuthorizedSigner(address extracted) internal view virtual returns (bool) {
        return extracted == authority.whitelistSigner();
    }

    function verifySignature(string memory data, bytes calldata signature) internal view {
        address extracted = getSigner(createHash(data), signature);
        require(isAuthorizedSigner(extracted), "Signature verification failed");
    }
}

File 19 of 19 : TheopetraAccessControlled.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.7.5;

import "../Interfaces/ITheopetraAuthority.sol";

abstract contract TheopetraAccessControlled {
    /* ========== EVENTS ========== */

    event AuthorityUpdated(ITheopetraAuthority indexed authority);

    string constant UNAUTHORIZED = "UNAUTHORIZED"; // save gas

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

    ITheopetraAuthority public authority;

    /* ========== Constructor ========== */

    constructor(ITheopetraAuthority _authority) {
        authority = _authority;
        emit AuthorityUpdated(_authority);
    }

    /* ========== MODIFIERS ========== */

    modifier onlyGovernor() {
        require(msg.sender == authority.governor(), UNAUTHORIZED);
        _;
    }

    modifier onlyGuardian() {
        require(msg.sender == authority.guardian(), UNAUTHORIZED);
        _;
    }

    modifier onlyPolicy() {
        require(msg.sender == authority.policy(), UNAUTHORIZED);
        _;
    }

    modifier onlyManager() {
        require(msg.sender == authority.manager(), UNAUTHORIZED);
        _;
    }

    modifier onlyVault() {
        require(msg.sender == authority.vault(), UNAUTHORIZED);
        _;
    }

    /* ========== GOV ONLY ========== */

    function setAuthority(ITheopetraAuthority _newAuthority) external onlyGovernor {
        authority = _newAuthority;
        emit AuthorityUpdated(_newAuthority);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ITheopetraAuthority","name":"_authority","type":"address"},{"internalType":"contract IERC20","name":"_theo","type":"address"},{"internalType":"contract IStakedTHEOToken","name":"_stheo","type":"address"},{"internalType":"contract IStaking","name":"_staking","type":"address"},{"internalType":"contract ITreasury","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract ITheopetraAuthority","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"Bond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CloseMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":true,"internalType":"address","name":"quoteToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fixedBondPrice","type":"uint256"}],"name":"CreateMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"noteId","type":"uint256"}],"name":"PullNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"noteId","type":"uint256"}],"name":"PushNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"toRef","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toDao","type":"uint256"}],"name":"SetRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"secret","type":"string"}],"name":"SetSecret","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract ITheopetraAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"calculatePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_quoteToken","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"uint256[2]","name":"_market","type":"uint256[2]"},{"internalType":"bool[2]","name":"_booleans","type":"bool[2]"},{"internalType":"uint256[2]","name":"_terms","type":"uint256[2]"}],"name":"create","outputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"daoReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxPrice","type":"uint256"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_referral","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"deposit","outputs":[{"components":[{"internalType":"uint256","name":"payout_","type":"uint256"},{"internalType":"uint256","name":"expiry_","type":"uint256"},{"internalType":"uint256","name":"index_","type":"uint256"}],"internalType":"struct IWhitelistBondDepository.DepositInfo","name":"depositInfo","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"priceFeedAddress","type":"address"}],"name":"getLatestPrice","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getMarketsFor","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getNotesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"indexesFor","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"isLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liveMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"liveMarketsFor","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"markets","outputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"contract IERC20","name":"quoteToken","type":"address"},{"internalType":"address","name":"priceFeed","type":"address"},{"internalType":"bool","name":"capacityInQuote","type":"bool"},{"internalType":"uint64","name":"sold","type":"uint64"},{"internalType":"uint256","name":"purchased","type":"uint256"},{"internalType":"uint256","name":"usdPricePerTHEO","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"marketsForQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"metadata","outputs":[{"internalType":"uint8","name":"quoteDecimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"notes","outputs":[{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint48","name":"created","type":"uint48"},{"internalType":"uint48","name":"matured","type":"uint48"},{"internalType":"uint48","name":"redeemed","type":"uint48"},{"internalType":"uint48","name":"marketID","type":"uint48"},{"internalType":"uint48","name":"discount","type":"uint48"},{"internalType":"bool","name":"autoStake","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"payoutFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"pendingFor","outputs":[{"internalType":"uint256","name":"payout_","type":"uint256"},{"internalType":"uint48","name":"created_","type":"uint48"},{"internalType":"uint48","name":"expiry_","type":"uint48"},{"internalType":"uint48","name":"timeRemaining_","type":"uint48"},{"internalType":"bool","name":"matured_","type":"bool"},{"internalType":"uint48","name":"discount_","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"pullNote","outputs":[{"internalType":"uint256","name":"newIndex_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"pushNote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256[]","name":"_indexes","type":"uint256[]"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"payout_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"redeemAll","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ITheopetraAuthority","name":"_newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_toFrontEnd","type":"uint256"},{"internalType":"uint256","name":"_toDAO","type":"uint256"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"secret","type":"string"}],"name":"setSecret","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"terms","outputs":[{"internalType":"bool","name":"fixedTerm","type":"bool"},{"internalType":"uint48","name":"vesting","type":"uint48"},{"internalType":"uint48","name":"conclusion","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"whitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b506040516200412038038062004120833981016040819052620000349162000164565b600080546001600160a01b0319166001600160a01b038716908117825560405187928792879287928792879287928492917f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad9190a2506001600160a01b0390811660805293841660a0525090821660c052600880546001600160a01b03191691831691909117905560405163095ea7b360e01b81528582166004820152722cd76fe086b93ce2f768a00b22a000000000006024820152908716925063095ea7b391506044016020604051808303816000875af115801562000119573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013f9190620001e4565b5050505050506200020f565b6001600160a01b03811681146200016157600080fd5b50565b600080600080600060a086880312156200017d57600080fd5b85516200018a816200014b565b60208701519095506200019d816200014b565b6040870151909450620001b0816200014b565b6060870151909350620001c3816200014b565b6080870151909250620001d6816200014b565b809150509295509295909350565b600060208284031215620001f757600080fd5b815180151581146200020857600080fd5b9392505050565b60805160a05160c051613ebe6200026260003960008181611df50152818161264901528181612f5e0152613014015260006127e9015260008181610a36015281816117f4015261274e0152613ebe6000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c8063ae1042651161012a578063c9b67af5116100bd578063e0b117ff1161008c578063e481b26511610071578063e481b26514610609578063ec2c90161461061c578063f3191a461461062457600080fd5b8063e0b117ff1461058b578063e3684e39146105e457600080fd5b8063c9b67af51461053a578063d2390aa214610542578063d6db4df814610555578063d936547e1461056857600080fd5b8063bf7e214f116100f9578063bf7e214f14610473578063c0680e201461049e578063c0aa0e8a146104b1578063c3e0fb1c146104ea57600080fd5b8063ae104265146103c6578063b1283e77146103d9578063b6d8eee014610437578063be399be51461046057600080fd5b8063654e51e7116101bd578063964561c41161018c5780639b19251a116101715780639b19251a146103985780639c769787146103ab578063a4220610146103b357600080fd5b8063964561c4146103505780639a1e46d51461038557600080fd5b8063654e51e7146103045780636a6c575d146103175780637a9e5e4b1461032a5780637ed6c9261461033d57600080fd5b806327507458116101f957806327507458146102a6578063333d7d77146102c95780633d18b912146102e957806364914439146102f157600080fd5b80630700037d1461022b5780630aebeb4e1461025e57806316345f18146102735780631885f5801461029d575b600080fd5b61024b61023936600461353a565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61027161026c366004613557565b61062d565b005b61028661028136600461353a565b610799565b6040805192835260ff909116602083015201610255565b61024b60015481565b6102b96102b4366004613557565b610884565b6040519015158152602001610255565b6102dc6102d736600461353a565b6108f1565b6040516102559190613570565b6102716109fc565b6102dc6102ff36600461353a565b610aa7565b6102716103123660046135b4565b610c36565b61024b6103253660046135b4565b610d4b565b61027161033836600461353a565b610dc2565b61027161034b36600461361f565b610ee4565b61036361035e366004613661565b610fef565b6040805182518152602080840151908201529181015190820152606001610255565b61024b6103933660046137aa565b6113a7565b6102716103a636600461353a565b61184b565b610271611941565b61024b6103c136600461385c565b611c12565b61024b6103d4366004613557565b612103565b6103ec6103e7366004613557565b61219a565b604080519788526001600160a01b0396871660208901529490951693860193909352901515606085015267ffffffffffffffff16608084015260a083015260c082015260e001610255565b61024b61044536600461353a565b6001600160a01b031660009081526005602052604090205490565b61024b61046e36600461353a565b612218565b600054610486906001600160a01b031681565b6040516001600160a01b039091168152602001610255565b61024b6104ac36600461385c565b612227565b6104c46104bf366004613557565b612258565b60408051931515845265ffffffffffff9283166020850152911690820152606001610255565b6104fd6104f836600461385c565b612298565b6040805196875265ffffffffffff9586166020880152938516938601939093529083166060850152151560808401521660a082015260c001610255565b6102dc6123e1565b61024b610550366004613888565b6124ca565b61027161056336600461385c565b612861565b6102b961057636600461353a565b60046020526000908152604090205460ff1681565b61059e61059936600461385c565b612966565b6040805197885265ffffffffffff96871660208901529486169487019490945291841660608601528316608085015290911660a0830152151560c082015260e001610255565b6105f76105f2366004613557565b6129eb565b60405160ff9091168152602001610255565b6102dc61061736600461353a565b612a0f565b6102dc612c60565b61024b60025481565b60008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a29190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906107025760405162461bcd60e51b81526004016106f99190613990565b60405180910390fd5b5042600b8281548110610717576107176139c3565b9060005260206000200160000160076101000a81548165ffffffffffff021916908365ffffffffffff1602179055506000600a828154811061075b5761075b6139c3565b6000918252602082206005909102019190915560405182917f8401d05adbea6548a6999cc1540766e6d2ff919292142862893d0e62ec79fbe591a250565b6000806000806000806000876001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156107e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080691906139f8565b945094509450945094506000886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108749190613a48565b9499949850939650505050505050565b6000600a8281548110610899576108996139c3565b9060005260206000209060050201600001546000141580156108eb575042600b83815481106108ca576108ca6139c3565b600091825260209091200154670100000000000000900465ffffffffffff16115b92915050565b6001600160a01b0381166000908152600d6020908152604080832080548251818502810185019093528083526060949383018282801561095057602002820191906000526020600020905b81548152602001906001019080831161093c575b505050505090506000815167ffffffffffffffff811115610973576109736136e7565b60405190808252806020026020018201604052801561099c578160200160208202803683370190505b50905060005b82518110156109f4578281815181106109bd576109bd6139c3565b60200260200101518282815181106109d7576109d76139c3565b6020908102919091010152806109ec81613a81565b9150506109a2565b509392505050565b3360008181526003602052604080822080549290555163a9059cbb60e01b8152600481019290925260248201819052906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015610a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa39190613a9c565b5050565b6001600160a01b0381166000908152600d60209081526040808320805482518185028101850190935280835260609493830182828015610b0657602002820191906000526020600020905b815481526020019060010190808311610af2575b50505050509050600080600090505b8251811015610b6557610b40838281518110610b3357610b336139c3565b6020026020010151610884565b15610b535781610b4f81613a81565b9250505b80610b5d81613a81565b915050610b15565b5060008167ffffffffffffffff811115610b8157610b816136e7565b604051908082528060200260200182016040528015610baa578160200160208202803683370190505b5090506000805b8451811015610c2b57610bcf858281518110610b3357610b336139c3565b15610c1957848181518110610be657610be66139c3565b6020026020010151838381518110610c0057610c006139c3565b602090810291909101015281610c1581613a81565b9250505b80610c2381613a81565b915050610bb1565b509095945050505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cab9190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610d025760405162461bcd60e51b81526004016106f99190613990565b506002829055600181905560408051838152602081018390527f41ddb6f76c2aab8405d1cca4bd752e126ac8976c1203888790f8594c7ba3661191015b60405180910390a15050565b600080600c8381548110610d6157610d616139c3565b6000918252602091829020604080519384019052015460ff16808252909150610d8b90600a613b9d565b610d9484612103565b610da686670de0b6b3a7640000613bac565b610db09190613be1565b610dba9190613be1565b949350505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e379190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610e8e5760405162461bcd60e51b81526004016106f99190613990565b506000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad91a250565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f599190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610fb05760405162461bcd60e51b81526004016106f99190613990565b50610fbd60098383613489565b507fc84ba0d041142642d7c555ad8e697a8d84a7bc3fdf46d377be42ef3ad71b5eda8282604051610d3f929190613bf5565b61101360405180606001604052806000815260200160008152602001600081525090565b6000600a8981548110611028576110286139c3565b906000526020600020906005020190506000600b8a8154811061104d5761104d6139c3565b600091825260209182902060408051606081018252919092015460ff81161515825265ffffffffffff610100820481169483019490945267010000000000000090048316918101829052925042918216106110ea5760405162461bcd60e51b815260206004820152601c60248201527f4465706f7369746f72793a206d61726b657420636f6e636c756465640000000060448201526064016106f9565b60006110f58c612103565b9050898111156111475760405162461bcd60e51b815260206004820152601f60248201527f4465706f7369746f72793a206d6f7265207468616e206d61782070726963650060448201526064016106f9565b600c8c8154811061115a5761115a6139c3565b6000918252602090912001546111749060ff16600a613b9d565b816111878d670de0b6b3a7640000613bac565b6111919190613be1565b61119b9190613be1565b85526002840154600160a01b900460ff166111b75784516111b9565b8a5b845410156112095760405162461bcd60e51b815260206004820152601d60248201527f4465706f7369746f72793a20636170616369747920657863656564656400000060448201526064016106f9565b6002840154600160a01b900460ff16611223578451611225565b8a5b8460000160008282546112389190613c24565b9091555050835461126f576040518c907f8401d05adbea6548a6999cc1540766e6d2ff919292142862893d0e62ec79fbe590600090a25b825161127f57826020015161128f565b81836020015161128f9190613c3b565b65ffffffffffff1660208601526003840180548c91906000906112b3908490613c65565b909155505084516002850180546015906112f19084907501000000000000000000000000000000000000000000900467ffffffffffffffff16613c7d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508b7f7880508a48fd3aee88f7e15917d85e39c3ad059e51ad4aca9bb46e7b4938b9618c83604051611352929190918252602082015260400190565b60405180910390a261137289866000015187602001518f8c600080612cf0565b60408601526008546001850154611398916001600160a01b03918216913391168e6130a4565b50505050979650505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141f9190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906114765760405162461bcd60e51b81526004016106f99190613990565b506000866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114db9190613a48565b60ff169050600a805490509150600a6040518060e0016040528087600060028110611508576115086139c3565b60200201518152602001896001600160a01b03168152602001886001600160a01b0316815260200186600060028110611543576115436139c3565b602002015115158152602001600067ffffffffffffffff168152602001600081526020018760016002811061157a5761157a6139c3565b60209081029190910151909152825460018082018555600094855282852084516005909302019182558383015182820180546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff199091161790556040808601516002850180546060808a015160808b015167ffffffffffffffff167501000000000000000000000000000000000000000000027fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff911515600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090941695881695909517929092179190911692909217905560a0870151600386015560c090960151600490940193909355825194850183528984015115158552885165ffffffffffff9081168686019081528a8601518216878601908152600b80548087018255908a5297517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db99098018054925191517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009093169815157fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff169890981761010091841691909102177fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff166701000000000000009190921602179094558151808401835260ff8781168252600c8054808501825590885291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7909201805460ff1916929091169190911790558b8416808652600d8452828620805492830181558652948390200186905588820151815190815290517f00000000000000000000000000000000000000000000000000000000000000009093169286927f2f6ff727bd580b1d1b8332e28aa93ed4ec9d8b08d6e30d6b4c9f7aa63ca17f63928290030190a45095945050505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561189c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c09190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906119175760405162461bcd60e51b81526004016106f99190613990565b506001600160a01b03166000908152600460205260409020805460ff19811660ff90911615179055565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b69190613943565b6001600160a01b0316336001600160a01b03161480611a5a575060008054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a459190613943565b6001600160a01b0316336001600160a01b0316145b80611aea575060008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad59190613943565b6001600160a01b0316336001600160a01b0316145b611b365760405162461bcd60e51b815260206004820152600f60248201527f4f6e6c7920617574686f72697a6564000000000000000000000000000000000060448201526064016106f9565b60008060009054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bae9190613943565b6008805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081529091507f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d19060200160405180910390a150565b6001600160a01b0382811660009081526006602090815260408083208584529091528120549091163314611c885760405162461bcd60e51b815260206004820152601e60248201527f4465706f7369746f72793a207472616e73666572206e6f7420666f756e64000060448201526064016106f9565b6001600160a01b0383166000908152600560205260409020805483908110611cb257611cb26139c3565b60009182526020909120600290910201600101546c01000000000000000000000000900465ffffffffffff1615611d2b5760405162461bcd60e51b815260206004820152601960248201527f4465706f7369746f72793a206e6f74652072656465656d65640000000000000060448201526064016106f9565b5033600090815260056020526040808220546001600160a01b03851683529120805483908110611d5d57611d5d6139c3565b9060005260206000209060020201600101601e9054906101000a900460ff1615611e53576001600160a01b038381166000908152600760208181526040808420878552825280842054338086529383528185208786529092529283902081905591517f78f1f77800000000000000000000000000000000000000000000000000000000815260048101919091526024810182905290917f000000000000000000000000000000000000000000000000000000000000000016906378f1f77890604401600060405180830381600087803b158015611e3957600080fd5b505af1158015611e4d573d6000803e3d6000fd5b50505050505b336000908152600560205260408082206001600160a01b03861683529120805484908110611e8357611e836139c3565b60009182526020808320845460018181018755958552828520600294850290920180549190940290910190815591840180549290940180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000811665ffffffffffff948516908117835586546601000000000000908190048616026bffffffffffffffffffffffff19909216171780825585546c01000000000000000000000000908190048516027fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff8216811783558654600160901b908190048616027fffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff9091167fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff90921691909117178082558554600160c01b908190049094169093027fffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff841681178255945460ff600160f01b91829004161515027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9095167fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff909316929092179390931790556001600160a01b0385168152600590915260409020805483908110612072576120726139c3565b60009182526020808320600292909202909101918255600190910180547fff00000000000000000000000000000000000000000000000000000000000000169055604080516001600160a01b0386168152339281019290925281018390527fac662197bb43cbfbf62b5caf539eb823ba3ee6f13941f9978304958a2c916ebf9060600160405180910390a192915050565b6000806000612140600a858154811061211e5761211e6139c3565b60009182526020909120600260059092020101546001600160a01b0316610799565b915091506000612182600a868154811061215c5761215c6139c3565b906000526020600020906005020160040154600984600961217d9190613ca0565b6131f6565b905060006121908483613cc5565b9695505050505050565b600a81815481106121aa57600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401549294506001600160a01b039182169391811692600160a01b820460ff1692750100000000000000000000000000000000000000000090920467ffffffffffffffff16919087565b60006108eb8261055084612a0f565b600d602052816000526040600020818154811061224357600080fd5b90600052602060002001600091509150505481565b600b818154811061226857600080fd5b60009182526020909120015460ff8116915065ffffffffffff610100820481169167010000000000000090041683565b6000806000806000806000600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002088815481106122d9576122d96139c3565b60009182526020918290206040805160e0810182526002909302909101805480845260019091015465ffffffffffff8082169585018690526601000000000000820481169385018490526c01000000000000000000000000820481166060860152600160901b820481166080860152600160c01b82041660a085015260ff600160f01b90910416151560c08401529950919750909550905042851161237f576000612397565b42816040015165ffffffffffff166123979190613c24565b9350806060015165ffffffffffff1660001480156123c1575042816040015165ffffffffffff1611155b80156123cd5750805115155b92508060a001519150509295509295509295565b60606000805b600a5481101561241f576123fa81610884565b1561240d578161240981613a81565b9250505b8061241781613a81565b9150506123e7565b5060008167ffffffffffffffff81111561243b5761243b6136e7565b604051908082528060200260200182016040528015612464578160200160208202803683370190505b5090506000805b600a548110156124c15761247e81610884565b156124af5780838381518110612496576124966139c3565b6020908102919091010152816124ab81613a81565b9250505b806124b981613a81565b91505061246b565b50909392505050565b6000428180805b855181101561272157600080612500898985815181106124f3576124f36139c3565b6020026020010151612298565b5094505050509150801561270c576001600160a01b038916600090815260056020526040902088518791908a908690811061253d5761253d6139c3565b602002602001015181548110612555576125556139c3565b9060005260206000209060020201600101600c6101000a81548165ffffffffffff021916908365ffffffffffff16021790555081876125949190613c65565b6001600160a01b038a1660009081526005602052604090208951919850908990859081106125c4576125c46139c3565b6020026020010151815481106125dc576125dc6139c3565b9060005260206000209060020201600101601e9054906101000a900460ff16156126ff576001600160a01b0389166000908152600760205260408120895182908b908790811061262e5761262e6139c3565b602002602001015181526020019081526020016000205490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b3e504098b836040518363ffffffff1660e01b81526004016126a99291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af11580156126c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ec9190613d0f565b506126f78387613c65565b95505061270c565b6127098285613c65565b93505b5050808061271990613a81565b9150506124d1565b5080156127bd5760405163a9059cbb60e01b81526001600160a01b038781166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bb9190613a9c565b505b81156128585760405163a9059cbb60e01b81526001600160a01b038781166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612832573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128569190613a9c565b505b50505092915050565b336000908152600560205260409020805482908110612882576128826139c3565b600091825260209091206001600290920201015465ffffffffffff166128ea5760405162461bcd60e51b815260206004820152601a60248201527f4465706f7369746f72793a206e6f7465206e6f7420666f756e6400000000000060448201526064016106f9565b336000818152600660209081526040808320858452825291829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915582519384529083015281018290527f46a855c725ecb3b899b429c361a8e87ced35203a422c4324e83b6a43b0b70c2390606001610d3f565b6005602052816000526040600020818154811061298257600080fd5b60009182526020909120600290910201805460019091015490925065ffffffffffff8082169250660100000000000082048116916c010000000000000000000000008104821691600160901b8204811691600160c01b810490911690600160f01b900460ff1687565b600c81815481106129fb57600080fd5b60009182526020909120015460ff16905081565b6001600160a01b0381166000908152600560209081526040808320805482518185028101850190935280835260609493849084015b82821015612ae65760008481526020908190206040805160e081018252600286029092018054835260019081015465ffffffffffff80821685870152660100000000000082048116938501939093526c01000000000000000000000000810483166060850152600160901b810483166080850152600160c01b810490921660a0840152600160f01b90910460ff16151560c08301529083529092019101612a44565b505050509050600080600090505b8251811015612b7557828181518110612b0f57612b0f6139c3565b60200260200101516060015165ffffffffffff166000148015612b505750828181518110612b3f57612b3f6139c3565b602002602001015160000151600014155b15612b635781612b5f81613a81565b9250505b80612b6d81613a81565b915050612af4565b5060008167ffffffffffffffff811115612b9157612b916136e7565b604051908082528060200260200182016040528015612bba578160200160208202803683370190505b5090506000805b8451811015610c2b57848181518110612bdc57612bdc6139c3565b60200260200101516060015165ffffffffffff166000148015612c1d5750848181518110612c0c57612c0c6139c3565b602002602001015160000151600014155b15612c4e5780838381518110612c3557612c356139c3565b602090810291909101015281612c4a81613a81565b9250505b80612c5881613a81565b915050612bc1565b600a5460609060009067ffffffffffffffff811115612c8157612c816136e7565b604051908082528060200260200182016040528015612caa578160200160208202803683370190505b50905060005b600a54811015612cea5780828281518110612ccd57612ccd6139c3565b602090810291909101015280612ce281613a81565b915050612cb0565b50919050565b6001600160a01b03871660009081526005602090815260408083208054825160e0810184528b815265ffffffffffff4281168287019081528c8216958301958652606083018881528c8316608085019081528b841660a086019081528b151560c0870190815260018089018a55988c52998b209551600288029096019586559251949096018054975191519651925198511515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff998516600160c01b02999099167fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff938516600160901b027fffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff9886166c0100000000000000000000000002989098167fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9386166601000000000000026bffffffffffffffffffffffff19909a16969095169590951797909717169190911793909317929092169190911792909217905590612e848886613269565b6008549091506001600160a01b03166340c10f1930612ea3848c613c65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612f0157600080fd5b505af1158015612f15573d6000803e3d6000fd5b505050508215613098576040517f995846bd00000000000000000000000000000000000000000000000000000000815230600482015260248101899052600160448201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063995846bd9060640160408051808303816000875af1158015612fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd29190613d28565b6040517f78f1f7780000000000000000000000000000000000000000000000000000000081526001600160a01b038d81166004830152602482018390529193507f000000000000000000000000000000000000000000000000000000000000000090911691506378f1f77890604401600060405180830381600087803b15801561305b57600080fd5b505af115801561306f573d6000803e3d6000fd5b505050506001600160a01b038a1660009081526007602090815260408083208684529091529020555b50979650505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916131369190613d4c565b6000604051808303816000865af19150503d8060008114613173576040519150601f19603f3d011682016040523d82523d6000602084013e613178565b606091505b50915091508180156131a25750805115806131a25750808060200190518101906131a29190613a9c565b6131ee5760405162461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064016106f9565b505050505050565b60008160ff168360ff16101561322f576132108383613d68565b61321e9060ff16600a613d8b565b6132289085613d97565b9050613262565b8160ff168360ff16111561325f576132478284613d68565b6132559060ff16600a613d8b565b6132289085613cc5565b50825b9392505050565b6000806127106001548561327d9190613bac565b6132879190613be1565b905060006127106002548661329c9190613bac565b6132a69190613be1565b6001600160a01b03851660009081526004602052604090205490915060ff16156133ae576001600160a01b038416600090815260036020526040812080548392906132f2908490613c65565b9250508190555081600360008060009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015613350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133749190613943565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546133a39190613c65565b909155506134769050565b6133b88183613c65565b60008054604080517f452a93200000000000000000000000000000000000000000000000000000000081529051600393926001600160a01b03169163452a93209160048083019260209291908290030181865afa15801561341d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134419190613943565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546134709190613c65565b90915550505b6134808183613c65565b95945050505050565b82805461349590613e53565b90600052602060002090601f0160209004810192826134b757600085556134fd565b82601f106134d05782800160ff198235161785556134fd565b828001600101855582156134fd579182015b828111156134fd5782358255916020019190600101906134e2565b5061350992915061350d565b5090565b5b80821115613509576000815560010161350e565b6001600160a01b038116811461353757600080fd5b50565b60006020828403121561354c57600080fd5b813561326281613522565b60006020828403121561356957600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156135a85783518352928401929184019160010161358c565b50909695505050505050565b600080604083850312156135c757600080fd5b50508035926020909101359150565b60008083601f8401126135e857600080fd5b50813567ffffffffffffffff81111561360057600080fd5b60208301915083602082850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b823567ffffffffffffffff81111561364957600080fd5b613655858286016135d6565b90969095509350505050565b600080600080600080600060c0888a03121561367c57600080fd5b873596506020880135955060408801359450606088013561369c81613522565b935060808801356136ac81613522565b925060a088013567ffffffffffffffff8111156136c857600080fd5b6136d48a828b016135d6565b989b979a50959850939692959293505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613720576137206136e7565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561374f5761374f6136e7565b604052919050565b600082601f83011261376857600080fd5b6137706136fd565b80604084018581111561378257600080fd5b845b81811015610c2b578035845260209384019301613784565b801515811461353757600080fd5b600080600080600061010086880312156137c357600080fd5b85356137ce81613522565b94506020868101356137df81613522565b94506137ee8860408901613757565b935087609f8801126137ff57600080fd5b6138076136fd565b8060c089018a81111561381957600080fd5b60808a015b8181101561383e5780356138318161379c565b845292840192840161381e565b5081955061384c8b82613757565b9450505050509295509295909350565b6000806040838503121561386f57600080fd5b823561387a81613522565b946020939093013593505050565b6000806040838503121561389b57600080fd5b82356138a681613522565b915060208381013567ffffffffffffffff808211156138c457600080fd5b818601915086601f8301126138d857600080fd5b8135818111156138ea576138ea6136e7565b8060051b91506138fb848301613726565b818152918301840191848101908984111561391557600080fd5b938501935b838510156139335784358252938501939085019061391a565b8096505050505050509250929050565b60006020828403121561395557600080fd5b815161326281613522565b60005b8381101561397b578181015183820152602001613963565b8381111561398a576000848401525b50505050565b60208152600082518060208401526139af816040850160208701613960565b601f01601f19169190910160400192915050565b634e487b7160e01b600052603260045260246000fd5b805169ffffffffffffffffffff811681146139f357600080fd5b919050565b600080600080600060a08688031215613a1057600080fd5b613a19866139d9565b9450602086015193506040860151925060608601519150613a3c608087016139d9565b90509295509295909350565b600060208284031215613a5a57600080fd5b815160ff8116811461326257600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613a9557613a95613a6b565b5060010190565b600060208284031215613aae57600080fd5b81516132628161379c565b600181815b80851115613af4578160001904821115613ada57613ada613a6b565b80851615613ae757918102915b93841c9390800290613abe565b509250929050565b600082613b0b575060016108eb565b81613b18575060006108eb565b8160018114613b2e5760028114613b3857613b54565b60019150506108eb565b60ff841115613b4957613b49613a6b565b50506001821b6108eb565b5060208310610133831016604e8410600b8410161715613b77575081810a6108eb565b613b818383613ab9565b8060001904821115613b9557613b95613a6b565b029392505050565b600061326260ff841683613afc565b6000816000190483118215151615613bc657613bc6613a6b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082613bf057613bf0613bcb565b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082821015613c3657613c36613a6b565b500390565b600065ffffffffffff808316818516808303821115613c5c57613c5c613a6b565b01949350505050565b60008219821115613c7857613c78613a6b565b500190565b600067ffffffffffffffff808316818516808303821115613c5c57613c5c613a6b565b600060ff821660ff84168060ff03821115613cbd57613cbd613a6b565b019392505050565b600082613cd457613cd4613bcb565b60001983147f800000000000000000000000000000000000000000000000000000000000000083141615613d0a57613d0a613a6b565b500590565b600060208284031215613d2157600080fd5b5051919050565b60008060408385031215613d3b57600080fd5b505080516020909101519092909150565b60008251613d5e818460208701613960565b9190910192915050565b600060ff821660ff841680821015613d8257613d82613a6b565b90039392505050565b60006132628383613afc565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615613dd857613dd8613a6b565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615613e1357613e13613a6b565b60008712925087820587128484161615613e2f57613e2f613a6b565b87850587128184161615613e4557613e45613a6b565b505050929093029392505050565b600181811c90821680613e6757607f821691505b60208210811415612cea57634e487b7160e01b600052602260045260246000fdfea2646970667358221220855898bd14e388cbb045157f9108e3a10647ab178b587aa357aac4603c4f802e64736f6c634300080a0033000000000000000000000000fe9fab692c951eeb28345b3a22008f4057eaa232000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac2000000000000000000000000e249e013e7aabcc79726e9d62b0c2d89cdd69f5100000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff4000000000000000000000000f3143ae15dea73f4e8f32360f6b669173c854388

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102265760003560e01c8063ae1042651161012a578063c9b67af5116100bd578063e0b117ff1161008c578063e481b26511610071578063e481b26514610609578063ec2c90161461061c578063f3191a461461062457600080fd5b8063e0b117ff1461058b578063e3684e39146105e457600080fd5b8063c9b67af51461053a578063d2390aa214610542578063d6db4df814610555578063d936547e1461056857600080fd5b8063bf7e214f116100f9578063bf7e214f14610473578063c0680e201461049e578063c0aa0e8a146104b1578063c3e0fb1c146104ea57600080fd5b8063ae104265146103c6578063b1283e77146103d9578063b6d8eee014610437578063be399be51461046057600080fd5b8063654e51e7116101bd578063964561c41161018c5780639b19251a116101715780639b19251a146103985780639c769787146103ab578063a4220610146103b357600080fd5b8063964561c4146103505780639a1e46d51461038557600080fd5b8063654e51e7146103045780636a6c575d146103175780637a9e5e4b1461032a5780637ed6c9261461033d57600080fd5b806327507458116101f957806327507458146102a6578063333d7d77146102c95780633d18b912146102e957806364914439146102f157600080fd5b80630700037d1461022b5780630aebeb4e1461025e57806316345f18146102735780631885f5801461029d575b600080fd5b61024b61023936600461353a565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61027161026c366004613557565b61062d565b005b61028661028136600461353a565b610799565b6040805192835260ff909116602083015201610255565b61024b60015481565b6102b96102b4366004613557565b610884565b6040519015158152602001610255565b6102dc6102d736600461353a565b6108f1565b6040516102559190613570565b6102716109fc565b6102dc6102ff36600461353a565b610aa7565b6102716103123660046135b4565b610c36565b61024b6103253660046135b4565b610d4b565b61027161033836600461353a565b610dc2565b61027161034b36600461361f565b610ee4565b61036361035e366004613661565b610fef565b6040805182518152602080840151908201529181015190820152606001610255565b61024b6103933660046137aa565b6113a7565b6102716103a636600461353a565b61184b565b610271611941565b61024b6103c136600461385c565b611c12565b61024b6103d4366004613557565b612103565b6103ec6103e7366004613557565b61219a565b604080519788526001600160a01b0396871660208901529490951693860193909352901515606085015267ffffffffffffffff16608084015260a083015260c082015260e001610255565b61024b61044536600461353a565b6001600160a01b031660009081526005602052604090205490565b61024b61046e36600461353a565b612218565b600054610486906001600160a01b031681565b6040516001600160a01b039091168152602001610255565b61024b6104ac36600461385c565b612227565b6104c46104bf366004613557565b612258565b60408051931515845265ffffffffffff9283166020850152911690820152606001610255565b6104fd6104f836600461385c565b612298565b6040805196875265ffffffffffff9586166020880152938516938601939093529083166060850152151560808401521660a082015260c001610255565b6102dc6123e1565b61024b610550366004613888565b6124ca565b61027161056336600461385c565b612861565b6102b961057636600461353a565b60046020526000908152604090205460ff1681565b61059e61059936600461385c565b612966565b6040805197885265ffffffffffff96871660208901529486169487019490945291841660608601528316608085015290911660a0830152151560c082015260e001610255565b6105f76105f2366004613557565b6129eb565b60405160ff9091168152602001610255565b6102dc61061736600461353a565b612a0f565b6102dc612c60565b61024b60025481565b60008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561067e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a29190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906107025760405162461bcd60e51b81526004016106f99190613990565b60405180910390fd5b5042600b8281548110610717576107176139c3565b9060005260206000200160000160076101000a81548165ffffffffffff021916908365ffffffffffff1602179055506000600a828154811061075b5761075b6139c3565b6000918252602082206005909102019190915560405182917f8401d05adbea6548a6999cc1540766e6d2ff919292142862893d0e62ec79fbe591a250565b6000806000806000806000876001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156107e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080691906139f8565b945094509450945094506000886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108749190613a48565b9499949850939650505050505050565b6000600a8281548110610899576108996139c3565b9060005260206000209060050201600001546000141580156108eb575042600b83815481106108ca576108ca6139c3565b600091825260209091200154670100000000000000900465ffffffffffff16115b92915050565b6001600160a01b0381166000908152600d6020908152604080832080548251818502810185019093528083526060949383018282801561095057602002820191906000526020600020905b81548152602001906001019080831161093c575b505050505090506000815167ffffffffffffffff811115610973576109736136e7565b60405190808252806020026020018201604052801561099c578160200160208202803683370190505b50905060005b82518110156109f4578281815181106109bd576109bd6139c3565b60200260200101518282815181106109d7576109d76139c3565b6020908102919091010152806109ec81613a81565b9150506109a2565b509392505050565b3360008181526003602052604080822080549290555163a9059cbb60e01b8152600481019290925260248201819052906001600160a01b037f000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac2169063a9059cbb906044016020604051808303816000875af1158015610a7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa39190613a9c565b5050565b6001600160a01b0381166000908152600d60209081526040808320805482518185028101850190935280835260609493830182828015610b0657602002820191906000526020600020905b815481526020019060010190808311610af2575b50505050509050600080600090505b8251811015610b6557610b40838281518110610b3357610b336139c3565b6020026020010151610884565b15610b535781610b4f81613a81565b9250505b80610b5d81613a81565b915050610b15565b5060008167ffffffffffffffff811115610b8157610b816136e7565b604051908082528060200260200182016040528015610baa578160200160208202803683370190505b5090506000805b8451811015610c2b57610bcf858281518110610b3357610b336139c3565b15610c1957848181518110610be657610be66139c3565b6020026020010151838381518110610c0057610c006139c3565b602090810291909101015281610c1581613a81565b9250505b80610c2381613a81565b915050610bb1565b509095945050505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cab9190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610d025760405162461bcd60e51b81526004016106f99190613990565b506002829055600181905560408051838152602081018390527f41ddb6f76c2aab8405d1cca4bd752e126ac8976c1203888790f8594c7ba3661191015b60405180910390a15050565b600080600c8381548110610d6157610d616139c3565b6000918252602091829020604080519384019052015460ff16808252909150610d8b90600a613b9d565b610d9484612103565b610da686670de0b6b3a7640000613bac565b610db09190613be1565b610dba9190613be1565b949350505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e379190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610e8e5760405162461bcd60e51b81526004016106f99190613990565b506000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f2f658b440c35314f52658ea8a740e05b284cdc84dc9ae01e891f21b8933e7cad91a250565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f599190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b81525090610fb05760405162461bcd60e51b81526004016106f99190613990565b50610fbd60098383613489565b507fc84ba0d041142642d7c555ad8e697a8d84a7bc3fdf46d377be42ef3ad71b5eda8282604051610d3f929190613bf5565b61101360405180606001604052806000815260200160008152602001600081525090565b6000600a8981548110611028576110286139c3565b906000526020600020906005020190506000600b8a8154811061104d5761104d6139c3565b600091825260209182902060408051606081018252919092015460ff81161515825265ffffffffffff610100820481169483019490945267010000000000000090048316918101829052925042918216106110ea5760405162461bcd60e51b815260206004820152601c60248201527f4465706f7369746f72793a206d61726b657420636f6e636c756465640000000060448201526064016106f9565b60006110f58c612103565b9050898111156111475760405162461bcd60e51b815260206004820152601f60248201527f4465706f7369746f72793a206d6f7265207468616e206d61782070726963650060448201526064016106f9565b600c8c8154811061115a5761115a6139c3565b6000918252602090912001546111749060ff16600a613b9d565b816111878d670de0b6b3a7640000613bac565b6111919190613be1565b61119b9190613be1565b85526002840154600160a01b900460ff166111b75784516111b9565b8a5b845410156112095760405162461bcd60e51b815260206004820152601d60248201527f4465706f7369746f72793a20636170616369747920657863656564656400000060448201526064016106f9565b6002840154600160a01b900460ff16611223578451611225565b8a5b8460000160008282546112389190613c24565b9091555050835461126f576040518c907f8401d05adbea6548a6999cc1540766e6d2ff919292142862893d0e62ec79fbe590600090a25b825161127f57826020015161128f565b81836020015161128f9190613c3b565b65ffffffffffff1660208601526003840180548c91906000906112b3908490613c65565b909155505084516002850180546015906112f19084907501000000000000000000000000000000000000000000900467ffffffffffffffff16613c7d565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508b7f7880508a48fd3aee88f7e15917d85e39c3ad059e51ad4aca9bb46e7b4938b9618c83604051611352929190918252602082015260400190565b60405180910390a261137289866000015187602001518f8c600080612cf0565b60408601526008546001850154611398916001600160a01b03918216913391168e6130a4565b50505050979650505050505050565b60008060009054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141f9190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906114765760405162461bcd60e51b81526004016106f99190613990565b506000866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114db9190613a48565b60ff169050600a805490509150600a6040518060e0016040528087600060028110611508576115086139c3565b60200201518152602001896001600160a01b03168152602001886001600160a01b0316815260200186600060028110611543576115436139c3565b602002015115158152602001600067ffffffffffffffff168152602001600081526020018760016002811061157a5761157a6139c3565b60209081029190910151909152825460018082018555600094855282852084516005909302019182558383015182820180546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff199091161790556040808601516002850180546060808a015160808b015167ffffffffffffffff167501000000000000000000000000000000000000000000027fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff911515600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090941695881695909517929092179190911692909217905560a0870151600386015560c090960151600490940193909355825194850183528984015115158552885165ffffffffffff9081168686019081528a8601518216878601908152600b80548087018255908a5297517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db99098018054925191517fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000009093169815157fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000ff169890981761010091841691909102177fffffffffffffffffffffffffffffffffffffff000000000000ffffffffffffff166701000000000000009190921602179094558151808401835260ff8781168252600c8054808501825590885291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7909201805460ff1916929091169190911790558b8416808652600d8452828620805492830181558652948390200186905588820151815190815290517f000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac29093169286927f2f6ff727bd580b1d1b8332e28aa93ed4ec9d8b08d6e30d6b4c9f7aa63ca17f63928290030190a45095945050505050565b60008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561189c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c09190613943565b6001600160a01b0316336001600160a01b0316146040518060400160405280600c81526020016b15539055551213d49256915160a21b815250906119175760405162461bcd60e51b81526004016106f99190613990565b506001600160a01b03166000908152600460205260409020805460ff19811660ff90911615179055565b60008054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b8152600401602060405180830381865afa158015611992573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119b69190613943565b6001600160a01b0316336001600160a01b03161480611a5a575060008054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a459190613943565b6001600160a01b0316336001600160a01b0316145b80611aea575060008054906101000a90046001600160a01b03166001600160a01b0316630505c8c96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad59190613943565b6001600160a01b0316336001600160a01b0316145b611b365760405162461bcd60e51b815260206004820152600f60248201527f4f6e6c7920617574686f72697a6564000000000000000000000000000000000060448201526064016106f9565b60008060009054906101000a90046001600160a01b03166001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bae9190613943565b6008805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081529091507f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d19060200160405180910390a150565b6001600160a01b0382811660009081526006602090815260408083208584529091528120549091163314611c885760405162461bcd60e51b815260206004820152601e60248201527f4465706f7369746f72793a207472616e73666572206e6f7420666f756e64000060448201526064016106f9565b6001600160a01b0383166000908152600560205260409020805483908110611cb257611cb26139c3565b60009182526020909120600290910201600101546c01000000000000000000000000900465ffffffffffff1615611d2b5760405162461bcd60e51b815260206004820152601960248201527f4465706f7369746f72793a206e6f74652072656465656d65640000000000000060448201526064016106f9565b5033600090815260056020526040808220546001600160a01b03851683529120805483908110611d5d57611d5d6139c3565b9060005260206000209060020201600101601e9054906101000a900460ff1615611e53576001600160a01b038381166000908152600760208181526040808420878552825280842054338086529383528185208786529092529283902081905591517f78f1f77800000000000000000000000000000000000000000000000000000000815260048101919091526024810182905290917f00000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff416906378f1f77890604401600060405180830381600087803b158015611e3957600080fd5b505af1158015611e4d573d6000803e3d6000fd5b50505050505b336000908152600560205260408082206001600160a01b03861683529120805484908110611e8357611e836139c3565b60009182526020808320845460018181018755958552828520600294850290920180549190940290910190815591840180549290940180547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000811665ffffffffffff948516908117835586546601000000000000908190048616026bffffffffffffffffffffffff19909216171780825585546c01000000000000000000000000908190048516027fffffffffffffffffffffffffffff000000000000ffffffffffffffffffffffff8216811783558654600160901b908190048616027fffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff9091167fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff90921691909117178082558554600160c01b908190049094169093027fffff000000000000ffffffffffffffffffffffffffffffffffffffffffffffff841681178255945460ff600160f01b91829004161515027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9095167fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff909316929092179390931790556001600160a01b0385168152600590915260409020805483908110612072576120726139c3565b60009182526020808320600292909202909101918255600190910180547fff00000000000000000000000000000000000000000000000000000000000000169055604080516001600160a01b0386168152339281019290925281018390527fac662197bb43cbfbf62b5caf539eb823ba3ee6f13941f9978304958a2c916ebf9060600160405180910390a192915050565b6000806000612140600a858154811061211e5761211e6139c3565b60009182526020909120600260059092020101546001600160a01b0316610799565b915091506000612182600a868154811061215c5761215c6139c3565b906000526020600020906005020160040154600984600961217d9190613ca0565b6131f6565b905060006121908483613cc5565b9695505050505050565b600a81815481106121aa57600080fd5b6000918252602090912060059091020180546001820154600283015460038401546004909401549294506001600160a01b039182169391811692600160a01b820460ff1692750100000000000000000000000000000000000000000090920467ffffffffffffffff16919087565b60006108eb8261055084612a0f565b600d602052816000526040600020818154811061224357600080fd5b90600052602060002001600091509150505481565b600b818154811061226857600080fd5b60009182526020909120015460ff8116915065ffffffffffff610100820481169167010000000000000090041683565b6000806000806000806000600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002088815481106122d9576122d96139c3565b60009182526020918290206040805160e0810182526002909302909101805480845260019091015465ffffffffffff8082169585018690526601000000000000820481169385018490526c01000000000000000000000000820481166060860152600160901b820481166080860152600160c01b82041660a085015260ff600160f01b90910416151560c08401529950919750909550905042851161237f576000612397565b42816040015165ffffffffffff166123979190613c24565b9350806060015165ffffffffffff1660001480156123c1575042816040015165ffffffffffff1611155b80156123cd5750805115155b92508060a001519150509295509295509295565b60606000805b600a5481101561241f576123fa81610884565b1561240d578161240981613a81565b9250505b8061241781613a81565b9150506123e7565b5060008167ffffffffffffffff81111561243b5761243b6136e7565b604051908082528060200260200182016040528015612464578160200160208202803683370190505b5090506000805b600a548110156124c15761247e81610884565b156124af5780838381518110612496576124966139c3565b6020908102919091010152816124ab81613a81565b9250505b806124b981613a81565b91505061246b565b50909392505050565b6000428180805b855181101561272157600080612500898985815181106124f3576124f36139c3565b6020026020010151612298565b5094505050509150801561270c576001600160a01b038916600090815260056020526040902088518791908a908690811061253d5761253d6139c3565b602002602001015181548110612555576125556139c3565b9060005260206000209060020201600101600c6101000a81548165ffffffffffff021916908365ffffffffffff16021790555081876125949190613c65565b6001600160a01b038a1660009081526005602052604090208951919850908990859081106125c4576125c46139c3565b6020026020010151815481106125dc576125dc6139c3565b9060005260206000209060020201600101601e9054906101000a900460ff16156126ff576001600160a01b0389166000908152600760205260408120895182908b908790811061262e5761262e6139c3565b602002602001015181526020019081526020016000205490507f00000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff46001600160a01b031663b3e504098b836040518363ffffffff1660e01b81526004016126a99291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af11580156126c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ec9190613d0f565b506126f78387613c65565b95505061270c565b6127098285613c65565b93505b5050808061271990613a81565b9150506124d1565b5080156127bd5760405163a9059cbb60e01b81526001600160a01b038781166004830152602482018390527f000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac2169063a9059cbb906044016020604051808303816000875af1158015612797573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127bb9190613a9c565b505b81156128585760405163a9059cbb60e01b81526001600160a01b038781166004830152602482018490527f000000000000000000000000e249e013e7aabcc79726e9d62b0c2d89cdd69f51169063a9059cbb906044016020604051808303816000875af1158015612832573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128569190613a9c565b505b50505092915050565b336000908152600560205260409020805482908110612882576128826139c3565b600091825260209091206001600290920201015465ffffffffffff166128ea5760405162461bcd60e51b815260206004820152601a60248201527f4465706f7369746f72793a206e6f7465206e6f7420666f756e6400000000000060448201526064016106f9565b336000818152600660209081526040808320858452825291829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915582519384529083015281018290527f46a855c725ecb3b899b429c361a8e87ced35203a422c4324e83b6a43b0b70c2390606001610d3f565b6005602052816000526040600020818154811061298257600080fd5b60009182526020909120600290910201805460019091015490925065ffffffffffff8082169250660100000000000082048116916c010000000000000000000000008104821691600160901b8204811691600160c01b810490911690600160f01b900460ff1687565b600c81815481106129fb57600080fd5b60009182526020909120015460ff16905081565b6001600160a01b0381166000908152600560209081526040808320805482518185028101850190935280835260609493849084015b82821015612ae65760008481526020908190206040805160e081018252600286029092018054835260019081015465ffffffffffff80821685870152660100000000000082048116938501939093526c01000000000000000000000000810483166060850152600160901b810483166080850152600160c01b810490921660a0840152600160f01b90910460ff16151560c08301529083529092019101612a44565b505050509050600080600090505b8251811015612b7557828181518110612b0f57612b0f6139c3565b60200260200101516060015165ffffffffffff166000148015612b505750828181518110612b3f57612b3f6139c3565b602002602001015160000151600014155b15612b635781612b5f81613a81565b9250505b80612b6d81613a81565b915050612af4565b5060008167ffffffffffffffff811115612b9157612b916136e7565b604051908082528060200260200182016040528015612bba578160200160208202803683370190505b5090506000805b8451811015610c2b57848181518110612bdc57612bdc6139c3565b60200260200101516060015165ffffffffffff166000148015612c1d5750848181518110612c0c57612c0c6139c3565b602002602001015160000151600014155b15612c4e5780838381518110612c3557612c356139c3565b602090810291909101015281612c4a81613a81565b9250505b80612c5881613a81565b915050612bc1565b600a5460609060009067ffffffffffffffff811115612c8157612c816136e7565b604051908082528060200260200182016040528015612caa578160200160208202803683370190505b50905060005b600a54811015612cea5780828281518110612ccd57612ccd6139c3565b602090810291909101015280612ce281613a81565b915050612cb0565b50919050565b6001600160a01b03871660009081526005602090815260408083208054825160e0810184528b815265ffffffffffff4281168287019081528c8216958301958652606083018881528c8316608085019081528b841660a086019081528b151560c0870190815260018089018a55988c52998b209551600288029096019586559251949096018054975191519651925198511515600160f01b027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff998516600160c01b02999099167fff00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff938516600160901b027fffffffffffffffff000000000000ffffffffffffffffffffffffffffffffffff9886166c0100000000000000000000000002989098167fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9386166601000000000000026bffffffffffffffffffffffff19909a16969095169590951797909717169190911793909317929092169190911792909217905590612e848886613269565b6008549091506001600160a01b03166340c10f1930612ea3848c613c65565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015612f0157600080fd5b505af1158015612f15573d6000803e3d6000fd5b505050508215613098576040517f995846bd00000000000000000000000000000000000000000000000000000000815230600482015260248101899052600160448201526000907f00000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff46001600160a01b03169063995846bd9060640160408051808303816000875af1158015612fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd29190613d28565b6040517f78f1f7780000000000000000000000000000000000000000000000000000000081526001600160a01b038d81166004830152602482018390529193507f00000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff490911691506378f1f77890604401600060405180830381600087803b15801561305b57600080fd5b505af115801561306f573d6000803e3d6000fd5b505050506001600160a01b038a1660009081526007602090815260408083208684529091529020555b50979650505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905291516000928392908816916131369190613d4c565b6000604051808303816000865af19150503d8060008114613173576040519150601f19603f3d011682016040523d82523d6000602084013e613178565b606091505b50915091508180156131a25750805115806131a25750808060200190518101906131a29190613a9c565b6131ee5760405162461bcd60e51b815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064016106f9565b505050505050565b60008160ff168360ff16101561322f576132108383613d68565b61321e9060ff16600a613d8b565b6132289085613d97565b9050613262565b8160ff168360ff16111561325f576132478284613d68565b6132559060ff16600a613d8b565b6132289085613cc5565b50825b9392505050565b6000806127106001548561327d9190613bac565b6132879190613be1565b905060006127106002548661329c9190613bac565b6132a69190613be1565b6001600160a01b03851660009081526004602052604090205490915060ff16156133ae576001600160a01b038416600090815260036020526040812080548392906132f2908490613c65565b9250508190555081600360008060009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015613350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133749190613943565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546133a39190613c65565b909155506134769050565b6133b88183613c65565b60008054604080517f452a93200000000000000000000000000000000000000000000000000000000081529051600393926001600160a01b03169163452a93209160048083019260209291908290030181865afa15801561341d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134419190613943565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546134709190613c65565b90915550505b6134808183613c65565b95945050505050565b82805461349590613e53565b90600052602060002090601f0160209004810192826134b757600085556134fd565b82601f106134d05782800160ff198235161785556134fd565b828001600101855582156134fd579182015b828111156134fd5782358255916020019190600101906134e2565b5061350992915061350d565b5090565b5b80821115613509576000815560010161350e565b6001600160a01b038116811461353757600080fd5b50565b60006020828403121561354c57600080fd5b813561326281613522565b60006020828403121561356957600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b818110156135a85783518352928401929184019160010161358c565b50909695505050505050565b600080604083850312156135c757600080fd5b50508035926020909101359150565b60008083601f8401126135e857600080fd5b50813567ffffffffffffffff81111561360057600080fd5b60208301915083602082850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b823567ffffffffffffffff81111561364957600080fd5b613655858286016135d6565b90969095509350505050565b600080600080600080600060c0888a03121561367c57600080fd5b873596506020880135955060408801359450606088013561369c81613522565b935060808801356136ac81613522565b925060a088013567ffffffffffffffff8111156136c857600080fd5b6136d48a828b016135d6565b989b979a50959850939692959293505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613720576137206136e7565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561374f5761374f6136e7565b604052919050565b600082601f83011261376857600080fd5b6137706136fd565b80604084018581111561378257600080fd5b845b81811015610c2b578035845260209384019301613784565b801515811461353757600080fd5b600080600080600061010086880312156137c357600080fd5b85356137ce81613522565b94506020868101356137df81613522565b94506137ee8860408901613757565b935087609f8801126137ff57600080fd5b6138076136fd565b8060c089018a81111561381957600080fd5b60808a015b8181101561383e5780356138318161379c565b845292840192840161381e565b5081955061384c8b82613757565b9450505050509295509295909350565b6000806040838503121561386f57600080fd5b823561387a81613522565b946020939093013593505050565b6000806040838503121561389b57600080fd5b82356138a681613522565b915060208381013567ffffffffffffffff808211156138c457600080fd5b818601915086601f8301126138d857600080fd5b8135818111156138ea576138ea6136e7565b8060051b91506138fb848301613726565b818152918301840191848101908984111561391557600080fd5b938501935b838510156139335784358252938501939085019061391a565b8096505050505050509250929050565b60006020828403121561395557600080fd5b815161326281613522565b60005b8381101561397b578181015183820152602001613963565b8381111561398a576000848401525b50505050565b60208152600082518060208401526139af816040850160208701613960565b601f01601f19169190910160400192915050565b634e487b7160e01b600052603260045260246000fd5b805169ffffffffffffffffffff811681146139f357600080fd5b919050565b600080600080600060a08688031215613a1057600080fd5b613a19866139d9565b9450602086015193506040860151925060608601519150613a3c608087016139d9565b90509295509295909350565b600060208284031215613a5a57600080fd5b815160ff8116811461326257600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613a9557613a95613a6b565b5060010190565b600060208284031215613aae57600080fd5b81516132628161379c565b600181815b80851115613af4578160001904821115613ada57613ada613a6b565b80851615613ae757918102915b93841c9390800290613abe565b509250929050565b600082613b0b575060016108eb565b81613b18575060006108eb565b8160018114613b2e5760028114613b3857613b54565b60019150506108eb565b60ff841115613b4957613b49613a6b565b50506001821b6108eb565b5060208310610133831016604e8410600b8410161715613b77575081810a6108eb565b613b818383613ab9565b8060001904821115613b9557613b95613a6b565b029392505050565b600061326260ff841683613afc565b6000816000190483118215151615613bc657613bc6613a6b565b500290565b634e487b7160e01b600052601260045260246000fd5b600082613bf057613bf0613bcb565b500490565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082821015613c3657613c36613a6b565b500390565b600065ffffffffffff808316818516808303821115613c5c57613c5c613a6b565b01949350505050565b60008219821115613c7857613c78613a6b565b500190565b600067ffffffffffffffff808316818516808303821115613c5c57613c5c613a6b565b600060ff821660ff84168060ff03821115613cbd57613cbd613a6b565b019392505050565b600082613cd457613cd4613bcb565b60001983147f800000000000000000000000000000000000000000000000000000000000000083141615613d0a57613d0a613a6b565b500590565b600060208284031215613d2157600080fd5b5051919050565b60008060408385031215613d3b57600080fd5b505080516020909101519092909150565b60008251613d5e818460208701613960565b9190910192915050565b600060ff821660ff841680821015613d8257613d82613a6b565b90039392505050565b60006132628383613afc565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615613dd857613dd8613a6b565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615613e1357613e13613a6b565b60008712925087820587128484161615613e2f57613e2f613a6b565b87850587128184161615613e4557613e45613a6b565b505050929093029392505050565b600181811c90821680613e6757607f821691505b60208210811415612cea57634e487b7160e01b600052602260045260246000fdfea2646970667358221220855898bd14e388cbb045157f9108e3a10647ab178b587aa357aac4603c4f802e64736f6c634300080a0033

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

000000000000000000000000fe9fab692c951eeb28345b3a22008f4057eaa232000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac2000000000000000000000000e249e013e7aabcc79726e9d62b0c2d89cdd69f5100000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff4000000000000000000000000f3143ae15dea73f4e8f32360f6b669173c854388

-----Decoded View---------------
Arg [0] : _authority (address): 0xfe9fAb692c951eeB28345B3A22008f4057eAa232
Arg [1] : _theo (address): 0xfAc0403a24229d7e2Edd994D50F5940624CBeac2
Arg [2] : _stheo (address): 0xE249e013E7AAbCC79726e9d62B0c2d89CdD69f51
Arg [3] : _staking (address): 0x18Bba38a6F8427Ed2B65b5C6E9532CD80f93aFf4
Arg [4] : _treasury (address): 0xf3143ae15deA73F4E8F32360F6b669173c854388

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000fe9fab692c951eeb28345b3a22008f4057eaa232
Arg [1] : 000000000000000000000000fac0403a24229d7e2edd994d50f5940624cbeac2
Arg [2] : 000000000000000000000000e249e013e7aabcc79726e9d62b0c2d89cdd69f51
Arg [3] : 00000000000000000000000018bba38a6f8427ed2b65b5c6e9532cd80f93aff4
Arg [4] : 000000000000000000000000f3143ae15dea73f4e8f32360f6b669173c854388


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.