ETH Price: $2,063.76 (-0.97%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Method Block
From
To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MetadataFacet

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 23 : MetadataFacet.sol
/*
 * SPDX-License-Identifier: MIT
 */

pragma solidity ^0.7.6;
pragma experimental ABIEncoderV2;

import "./MetadataImage.sol";
import {LibBytes} from "contracts/libraries/LibBytes.sol";
import {LibTokenSilo} from "contracts/libraries/Silo/LibTokenSilo.sol";


/**
 * @title MetadataFacet
 * @author Brean
 * @notice MetadataFacet is a contract that provides metadata for beanstalk ERC1155 deposits, 
 * as well as other auxiliary functions related to ERC1155 deposits.
 * 
 * @dev Deposits are represented by a uint256, which is the concatination of the token address and the stem.
 */
contract MetadataFacet is MetadataImage {
    using LibStrings for uint256;
    using LibStrings for int256;

    event URI(string _uri, uint256 indexed _id);

    /**
     * @notice Returns the URI for a given depositId.
     * @param depositId - the id of the deposit
     * @dev the URI is a base64 encoded JSON object that contains the metadata and base64 encoded svg.
     * Deposits are stored as a mapping of a uint256 to a Deposit struct.
     * ERC20 deposits are represented by the concatination of the token address and the stem. (20 + 12 bytes).
     */
    function uri(uint256 depositId) external view returns (string memory) {
        (address token, int96 stem) = LibBytes.unpackAddressAndStem(depositId);
        int96 stemTip = LibTokenSilo.stemTipForToken(token);
        require(token != address(0), "Silo: metadata does not exist");
        bytes memory attributes = abi.encodePacked(
            ', "attributes": [ { "trait_type": "Token", "value": "', getTokenName(token),
            '"}, { "trait_type": "Token Address", "value": "', LibStrings.toHexString(uint256(token), 20),
            '"}, { "trait_type": "Id", "value": "', depositId.toHexString(32),
            '"}, { "trait_type": "stem", "display_type": "number", "value": ', int256(stem).toString(),
            '}, { "trait_type": "inital stalk per BDV", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkIssuedPerBdv(token)).toString(),
            '}, { "trait_type": "grown stalk per BDV", "display_type": "number", "value": ', uint256(stemTip - stem).toString(),
            '}, { "trait_type": "stalk grown per BDV per season", "display_type": "number", "value": ', uint256(LibTokenSilo.stalkEarnedPerSeason(token)).toString()
        );
        return string(abi.encodePacked("data:application/json;base64,",LibBytes64.encode(abi.encodePacked(
                '{',
                    '"name": "Beanstalk Silo Deposits", "description": "An ERC1155 representing an asset deposited in the Beanstalk Silo. Silo Deposits gain stalk and bean seignorage. ',
                    '\\n\\nDISCLAIMER: Due diligence is imperative when assessing this NFT. Opensea and other NFT marketplaces cache the svg output and thus, may require the user to refresh the metadata to properly show the correct values."',                    
                    attributes,
                    string(abi.encodePacked(', "image": "', imageURI(token, stem, stemTip), '"')),
                '}'
            ))
        ));
    }

    function name() external pure returns (string memory){
        return "Beanstalk Silo Deposits";
    }

    function symbol() external pure returns (string memory){
        return "DEPOSIT";
    }
}

File 2 of 23 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 3 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 4 of 23 : Counters.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "../math/SafeMath.sol";

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

File 5 of 23 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 6 of 23 : AppStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "../interfaces/IDiamondCut.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

/**
 * @title Account
 * @author Publius
 * @notice Stores Farmer-level Beanstalk state.
 * @dev {Account.State} is the primary struct that is referenced from {Storage.State}. 
 * All other structs in {Account} are referenced in {Account.State}. Each unique
 * Ethereum address is a Farmer.
 */
contract Account {
    /**
     * @notice Stores a Farmer's Plots and Pod allowances.
     * @param plots A Farmer's Plots. Maps from Plot index to Pod amount.
     * @param podAllowances An allowance mapping for Pods similar to that of the ERC-20 standard. Maps from spender address to allowance amount.
     */
    struct Field {
        mapping(uint256 => uint256) plots;
        mapping(address => uint256) podAllowances;
    }

    /**
     * @notice Stores a Farmer's Deposits and Seeds per Deposit, and formerly stored Withdrawals.
     * @param withdrawals DEPRECATED: Silo V1 Withdrawals are no longer referenced.
     * @param deposits Unripe Bean/LP Deposits (previously Bean/LP Deposits).
     * @param depositSeeds BDV of Unripe LP Deposits / 4 (previously # of Seeds in corresponding LP Deposit).
     */
    struct AssetSilo {
        mapping(uint32 => uint256) withdrawals;
        mapping(uint32 => uint256) deposits;
        mapping(uint32 => uint256) depositSeeds;
    }

    /**
     * @notice Represents a Deposit of a given Token in the Silo at a given Season.
     * @param amount The amount of Tokens in the Deposit.
     * @param bdv The Bean-denominated value of the total amount of Tokens in the Deposit.
     * @dev `amount` and `bdv` are packed as uint128 to save gas.
     */
    struct Deposit {
        uint128 amount; // ───┐ 16
        uint128 bdv; // ──────┘ 16 (32/32)
    }

    /**
     * @notice Stores a Farmer's Stalk and Seeds balances.
     * @param stalk Balance of the Farmer's Stalk.
     * @param seeds DEPRECATED – Balance of the Farmer's Seeds. Seeds are no longer referenced as of Silo V3.
     */
    struct Silo {
        uint256 stalk;
        uint256 seeds;
    }

    /**
     * @notice This struct stores the mow status for each Silo-able token, for each farmer. 
     * This gets updated each time a farmer mows, or adds/removes deposits.
     * @param lastStem The last cumulative grown stalk per bdv index at which the farmer mowed.
     * @param bdv The bdv of all of a farmer's deposits of this token type.
     * 
     */
    struct MowStatus {
        int96 lastStem; // ───┐ 12
        uint128 bdv; // ──────┘ 16 (28/32)
    }

    /**
     * @notice Stores a Farmer's Season of Plenty (SOP) balances.
     * @param roots The number of Roots a Farmer had when it started Raining.
     * @param plentyPerRoot The global Plenty Per Root index at the last time a Farmer updated their Silo.
     * @param plenty The balance of a Farmer's plenty. Plenty can be claimed directly for 3CRV.
     */
    struct SeasonOfPlenty {
        uint256 roots;
        uint256 plentyPerRoot;
        uint256 plenty;
    }
    
    /**
     * @notice Defines the state object for a Farmer.
     * @param field A Farmer's Field storage.
     * @param bean A Farmer's Unripe Bean Deposits only as a result of Replant (previously held the V1 Silo Deposits/Withdrawals for Beans).
     * @param lp A Farmer's Unripe LP Deposits as a result of Replant of BEAN:ETH Uniswap v2 LP Tokens (previously held the V1 Silo Deposits/Withdrawals for BEAN:ETH Uniswap v2 LP Tokens).
     * @param s A Farmer's Silo storage.
     * @param deprecated_votedUntil DEPRECATED – Replant removed on-chain governance including the ability to vote on BIPs.
     * @param lastUpdate The Season in which the Farmer last updated their Silo.
     * @param lastSop The last Season that a SOP occured at the time the Farmer last updated their Silo.
     * @param lastRain The last Season that it started Raining at the time the Farmer last updated their Silo.
     * @param deprecated_lastSIs DEPRECATED – In Silo V1.2, the Silo reward mechanism was updated to no longer need to store the number of the Supply Increases at the time the Farmer last updated their Silo.
     * @param deprecated_proposedUntil DEPRECATED – Replant removed on-chain governance including the ability to propose BIPs.
     * @param deprecated_sop DEPRECATED – Replant reset the Season of Plenty mechanism
     * @param roots A Farmer's Root balance.
     * @param deprecated_wrappedBeans DEPRECATED – Replant generalized Internal Balances. Wrapped Beans are now stored at the AppStorage level.
     * @param deposits A Farmer's Silo Deposits stored as a map from Token address to Season of Deposit to Deposit.
     * @param withdrawals A Farmer's Withdrawals from the Silo stored as a map from Token address to Season the Withdrawal becomes Claimable to Withdrawn amount of Tokens.
     * @param sop A Farmer's Season of Plenty storage.
     * @param depositAllowances A mapping of `spender => Silo token address => amount`.
     * @param tokenAllowances Internal balance token allowances.
     * @param depositPermitNonces A Farmer's current deposit permit nonce
     * @param tokenPermitNonces A Farmer's current token permit nonce
     */
    struct State {
        Field field; // A Farmer's Field storage.

        /*
         * @dev (Silo V1) A Farmer's Unripe Bean Deposits only as a result of Replant
         *
         * Previously held the V1 Silo Deposits/Withdrawals for Beans.

         * NOTE: While the Silo V1 format is now deprecated, this storage slot is used for gas
         * efficiency to store Unripe BEAN deposits. See {LibUnripeSilo} for more.
         */
        AssetSilo bean; 

        /*
         * @dev (Silo V1) Unripe LP Deposits as a result of Replant.
         * 
         * Previously held the V1 Silo Deposits/Withdrawals for BEAN:ETH Uniswap v2 LP Tokens.
         * 
         * BEAN:3CRV and BEAN:LUSD tokens prior to Replant were stored in the Silo V2
         * format in the `s.a[account].legacyDeposits` mapping.
         *
         * NOTE: While the Silo V1 format is now deprecated, unmigrated Silo V1 deposits are still
         * stored in this storage slot. See {LibUnripeSilo} for more.
         * 
         */
        AssetSilo lp; 

        /*
         * @dev Holds Silo specific state for each account.
         */
        Silo s;
        
        uint32 votedUntil; // DEPRECATED – Replant removed on-chain governance including the ability to vote on BIPs.
        uint32 lastUpdate; // The Season in which the Farmer last updated their Silo.
        uint32 lastSop; // The last Season that a SOP occured at the time the Farmer last updated their Silo.
        uint32 lastRain; // The last Season that it started Raining at the time the Farmer last updated their Silo.
        uint128 deltaRoots; // the number of roots to add, in the case where a farmer has mowed in the morning
        SeasonOfPlenty deprecated; // DEPRECATED – Replant reset the Season of Plenty mechanism
        uint256 roots; // A Farmer's Root balance.
        uint256 wrappedBeans; // DEPRECATED – Replant generalized Internal Balances. Wrapped Beans are now stored at the AppStorage level.
        mapping(address => mapping(uint32 => Deposit)) legacyDeposits; // Legacy Silo V2 Deposits stored as a map from Token address to Season of Deposit to Deposit. NOTE: While the Silo V2 format is now deprecated, unmigrated Silo V2 deposits are still stored in this mapping.
        mapping(address => mapping(uint32 => uint256)) withdrawals; // DEPRECATED - Zero withdraw eliminates a need for withdraw mapping
        SeasonOfPlenty sop; // A Farmer's Season Of Plenty storage.
        mapping(address => mapping(address => uint256)) depositAllowances; // Spender => Silo Token
        mapping(address => mapping(IERC20 => uint256)) tokenAllowances; // Token allowances
        uint256 depositPermitNonces; // A Farmer's current deposit permit nonce
        uint256 tokenPermitNonces; // A Farmer's current token permit nonce
        mapping(uint256 => Deposit) deposits; // SiloV3 Deposits stored as a map from uint256 to Deposit. This is an concat of the token address and the CGSPBDV for a ERC20 deposit, and a hash for an ERC721/1155 deposit.
        mapping(address => MowStatus) mowStatuses; // Store a MowStatus for each Whitelisted Silo token
        mapping(address => bool) isApprovedForAll; // ERC1155 isApprovedForAll mapping 
    }
}

/**
 * @title Storage
 * @author Publius
 * @notice Stores system-level Beanstalk state.
 */
contract Storage {
    /**
     * @notice DEPRECATED: System-level contract addresses.
     * @dev After Replant, Beanstalk stores Token addresses as constants to save gas.
     */
    struct Contracts {
        address bean;
        address pair;
        address pegPair;
        address weth;
    }

    /**
     * @notice System-level Field state variables.
     * @param soil The number of Soil currently available. Adjusted during {Sun.stepSun}.
     * @param beanSown The number of Bean sown within the current Season. Reset during {Weather.stepWeather}.
     * @param pods The pod index; the total number of Pods ever minted.
     * @param harvested The harvested index; the total number of Pods that have ever been Harvested.
     * @param harvestable The harvestable index; the total number of Pods that have ever been Harvestable. Included previously Harvested Beans.
     */
    struct Field {
        uint128 soil; // ──────┐ 16
        uint128 beanSown; // ──┘ 16 (32/32)
        uint256 pods;
        uint256 harvested;
        uint256 harvestable;
    }

    /**
     * @notice DEPRECATED: Contained data about each BIP (Beanstalk Improvement Proposal).
     * @dev Replant moved governance off-chain. This struct is left for future reference.
     * 
     */
    struct Bip {
        address proposer; // ───┐ 20
        uint32 start; //        │ 4 (24)
        uint32 period; //       │ 4 (28)
        bool executed; // ──────┘ 1 (29/32)
        int pauseOrUnpause; 
        uint128 timestamp;
        uint256 roots;
        uint256 endTotalRoots;
    }

    /**
     * @notice DEPRECATED: Contained data for the DiamondCut associated with each BIP.
     * @dev Replant moved governance off-chain. This struct is left for future reference.
     * @dev {Storage.DiamondCut} stored DiamondCut-related data for each {Bip}.
     */
    struct DiamondCut {
        IDiamondCut.FacetCut[] diamondCut;
        address initAddress;
        bytes initData;
    }

    /**
     * @notice DEPRECATED: Contained all governance-related data, including a list of BIPs, votes for each BIP, and the DiamondCut needed to execute each BIP.
     * @dev Replant moved governance off-chain. This struct is left for future reference.
     * @dev {Storage.Governance} stored all BIPs and Farmer voting information.
     */
    struct Governance {
        uint32[] activeBips;
        uint32 bipIndex;
        mapping(uint32 => DiamondCut) diamondCuts;
        mapping(uint32 => mapping(address => bool)) voted;
        mapping(uint32 => Bip) bips;
    }

    /**
     * @notice System-level Silo state; contains deposit and withdrawal data for a particular whitelisted Token.
     * @param deposited The total amount of this Token currently Deposited in the Silo.
     * @param depositedBdv The total bdv of this Token currently Deposited in the Silo.
     * @param withdrawn The total amount of this Token currently Withdrawn From the Silo.
     * @dev {Storage.State} contains a mapping from Token address => AssetSilo.
     * Currently, the bdv of deposits are asynchronous, and require an on-chain transaction to update.
     * Thus, the total bdv of deposits cannot be calculated, and must be stored and updated upon a bdv change.
     * 
     * Note that "Withdrawn" refers to the amount of Tokens that have been Withdrawn
     * but not yet Claimed. This will be removed in a future BIP.
     */
    struct AssetSilo {
        uint128 deposited;
        uint128 depositedBdv;
        uint256 withdrawn;
    }

    /**
     * @notice System-level Silo state variables.
     * @param stalk The total amount of active Stalk (including Earned Stalk, excluding Grown Stalk).
     * @param deprecated_seeds DEPRECATED: The total amount of active Seeds (excluding Earned Seeds).
     * @dev seeds are no longer used internally. Balance is wiped to 0 from the mayflower update. see {mowAndMigrate}.
     * @param roots The total amount of Roots.
     */
    struct Silo {
        uint256 stalk;
        uint256 deprecated_seeds; 
        uint256 roots;
    }

    /**
     * @notice System-level Curve Metapool Oracle state variables.
     * @param initialized True if the Oracle has been initialzed. It needs to be initialized on Deployment and re-initialized each Unpause.
     * @param startSeason The Season the Oracle started minting. Used to ramp up delta b when oracle is first added.
     * @param balances The cumulative reserve balances of the pool at the start of the Season (used for computing time weighted average delta b).
     * @param timestamp DEPRECATED: The timestamp of the start of the current Season. `LibCurveMinting` now uses `s.season.timestamp` instead of storing its own for gas efficiency purposes.
     * @dev Currently refers to the time weighted average deltaB calculated from the BEAN:3CRV pool.
     */
    struct CurveMetapoolOracle {
        bool initialized; // ────┐ 1
        uint32 startSeason; // ──┘ 4 (5/32)
        uint256[2] balances;
        uint256 timestamp;
    }

    /**
     * @notice System-level Rain balances. Rain occurs when P > 1 and the Pod Rate Excessively Low.
     * @dev The `raining` storage variable is stored in the Season section for a gas efficient read operation.
     * @param deprecated Previously held Rain start and Rain status variables. Now moved to Season struct for gas efficiency.
     * @param pods The number of Pods when it last started Raining.
     * @param roots The number of Roots when it last started Raining.
     */
    struct Rain {
        uint256 deprecated;
        uint256 pods;
        uint256 roots;
    }

    /**
     * @notice System-level Season state variables.
     * @param current The current Season in Beanstalk.
     * @param lastSop The Season in which the most recent consecutive series of Seasons of Plenty started.
     * @param withdrawSeasons The number of Seasons required to Withdraw a Deposit.
     * @param lastSopSeason The Season in which the most recent consecutive series of Seasons of Plenty ended.
     * @param rainStart Stores the most recent Season in which Rain started.
     * @param raining True if it is Raining (P > 1, Pod Rate Excessively Low).
     * @param fertilizing True if Beanstalk has Fertilizer left to be paid off.
     * @param sunriseBlock The block of the start of the current Season.
     * @param abovePeg Boolean indicating whether the previous Season was above or below peg.
     * @param stemStartSeason // season in which the stem storage method was introduced
     * @param start The timestamp of the Beanstalk deployment rounded down to the nearest hour.
     * @param period The length of each season in Beanstalk in seconds.
     * @param timestamp The timestamp of the start of the current Season.
     */
    struct Season {
        uint32 current; // ────────┐ 4  
        uint32 lastSop; //         │ 4 (8)
        uint8 withdrawSeasons; //  │ 1 (9)
        uint32 lastSopSeason; //   │ 4 (13)
        uint32 rainStart; //       │ 4 (17)
        bool raining; //           │ 1 (18)
        bool fertilizing; //       │ 1 (19)
        uint32 sunriseBlock; //    │ 4 (23)
        bool abovePeg; //          | 1 (24)
        uint16 stemStartSeason; // ┘ 2 (26/32)
        uint256 start;
        uint256 period;
        uint256 timestamp;
    }

    /**
     * @notice System-level Weather state variables.
     * @param deprecated 2 slots that were previously used.
     * @param lastDSoil Delta Soil; the number of Soil purchased last Season.
     * @param lastSowTime The number of seconds it for Soil to sell out last Season.
     * @param thisSowTime The number of seconds it for Soil to sell out this Season.
     * @param t The Temperature; the maximum interest rate during the current Season for sowing Beans in Soil. Adjusted each Season.
     */
    struct Weather {
        uint256[2] deprecated;
        uint128 lastDSoil;  // ───┐ 16 (16)
        uint32 lastSowTime; //    │ 4  (20)
        uint32 thisSowTime; //    │ 4  (24)
        uint32 t; // ─────────────┘ 4  (28/32)
    }

    /**
     * @notice Describes a Fundraiser.
     * @param payee The address to be paid after the Fundraiser has been fully funded.
     * @param token The token address that used to raise funds for the Fundraiser.
     * @param total The total number of Tokens that need to be raised to complete the Fundraiser.
     * @param remaining The remaining number of Tokens that need to to complete the Fundraiser.
     * @param start The timestamp at which the Fundraiser started (Fundraisers cannot be started and funded in the same block).
     */
    struct Fundraiser {
        address payee;
        address token;
        uint256 total;
        uint256 remaining;
        uint256 start;
    }

    /**
     * @notice Describes the settings for each Token that is Whitelisted in the Silo.
     * @param selector The encoded BDV function selector for the Token.
     * @param seeds The Seeds Per BDV that the Silo mints in exchange for Depositing this Token.
     * @param stalk The Stalk Per BDV that the Silo mints in exchange for Depositing this Token.
     * @dev A Token is considered Whitelisted if there exists a non-zero {SiloSettings} selector.
     * 
     * Note: `selector` is an encoded function selector that pertains to an 
     * external view function with the following signature:
     * 
     * `function tokenToBdv(uint256 amount) public view returns (uint256);`
     * 
     * It is called by {LibTokenSilo} through the use of delegate call to calculate 
     * the BDV of Tokens at the time of Deposit.
     */
    struct SiloSettings {
        /*
         * @dev: 
         * 
         * `selector` is an encoded function selector that pertains to 
         * an external view Beanstalk function with the following signature:
         * 
         * ```
         * function tokenToBdv(uint256 amount) public view returns (uint256);
         * ```
         * 
         * It is called by `LibTokenSilo` through the use of `delegatecall`
         * to calculate a token's BDV at the time of Deposit.
         */
        bytes4 selector;
        /*
         * @dev The Stalk Per BDV Per Season represents how much Stalk one BDV of the underlying deposited token
         * grows each season. In the past, this was represented by seeds. This is stored as 1e6, plus stalk is stored
         *  as 1e10, so 1 legacy seed would be 1e6 * 1e10.
         */
        uint32 stalkEarnedPerSeason;
        /*
         * @dev The Stalk Per BDV that the Silo grants in exchange for Depositing this Token.
         * previously just called stalk.
         */
        uint32 stalkIssuedPerBdv;
        /*
         * @dev The last season in which the stalkEarnedPerSeason for this token was updated
         */
		uint32 milestoneSeason;
        /*
         * @dev The cumulative amount of grown stalk per BDV for this Silo depositable token at the last stalkEarnedPerSeason update
         */
		int96 milestoneStem;

        /*
         @dev 1 byte of space is used for different encoding types.
         */
        bytes1 encodeType;

        /// @dev  7 bytes of additional storage space is available here.

    }

    /**
     * @notice Describes the settings for each Unripe Token in Beanstalk.
     * @param underlyingToken The address of the Token underlying the Unripe Token.
     * @param balanceOfUnderlying The number of Tokens underlying the Unripe Tokens (redemption pool).
     * @param merkleRoot The Merkle Root used to validate a claim of Unripe Tokens.
     * @dev An Unripe Token is a vesting Token that is redeemable for a a pro rata share
     * of the `balanceOfUnderlying`, subject to a penalty based on the percent of
     * Unfertilized Beans paid back.
     * 
     * There were two Unripe Tokens added at Replant: 
     *  - Unripe Bean, with its `underlyingToken` as BEAN;
     *  - Unripe LP, with its `underlyingToken` as BEAN:3CRV LP.
     * 
     * Unripe Tokens are initially distributed through the use of a `merkleRoot`.
     * 
     * The existence of a non-zero {UnripeSettings} implies that a Token is an Unripe Token.
     */
    struct UnripeSettings {
        address underlyingToken;
        uint256 balanceOfUnderlying;
        bytes32 merkleRoot;
    }
}

/**
 * @title AppStorage
 * @author Publius
 * @notice Defines the state object for Beanstalk.
 * @param deprecated_index DEPRECATED: Was the index of the BEAN token in the BEAN:ETH Uniswap V2 pool.
 * @param cases The 24 Weather cases (array has 32 items, but caseId = 3 (mod 4) are not cases)
 * @param paused True if Beanstalk is Paused.
 * @param pausedAt The timestamp at which Beanstalk was last paused.
 * @param season Storage.Season
 * @param c Storage.Contracts
 * @param f Storage.Field
 * @param g Storage.Governance
 * @param co Storage.CurveMetapoolOracle
 * @param r Storage.Rain
 * @param s Storage.Silo
 * @param reentrantStatus An intra-transaction state variable to protect against reentrance.
 * @param w Storage.Weather
 * @param earnedBeans The number of Beans distributed to the Silo that have not yet been Deposited as a result of the Earn function being called.
 * @param deprecated DEPRECATED - 14 slots that used to store state variables which have been deprecated through various updates. Storage slots can be left alone or reused.
 * @param a mapping (address => Account.State)
 * @param deprecated_bip0Start DEPRECATED - bip0Start was used to aid in a migration that occured alongside BIP-0.
 * @param deprecated_hotFix3Start DEPRECATED - hotFix3Start was used to aid in a migration that occured alongside HOTFIX-3.
 * @param fundraisers A mapping from Fundraiser ID to Storage.Fundraiser.
 * @param fundraiserIndex The number of Fundraisers that have occured.
 * @param deprecated_isBudget DEPRECATED - Budget Facet was removed in BIP-14. 
 * @param podListings A mapping from Plot Index to the hash of the Pod Listing.
 * @param podOrders A mapping from the hash of a Pod Order to the amount of Pods that the Pod Order is still willing to buy.
 * @param siloBalances A mapping from Token address to Silo Balance storage (amount deposited and withdrawn).
 * @param ss A mapping from Token address to Silo Settings for each Whitelisted Token. If a non-zero storage exists, a Token is whitelisted.
 * @param deprecated2 DEPRECATED - 2 slots that used to store state variables which have been depreciated through various updates. Storage slots can be left alone or reused.
 * @param newEarnedStalk the amount of earned stalk issued this season. Since 1 stalk = 1 bean, it represents the earned beans as well.
 * @param sops A mapping from Season to Plenty Per Root (PPR) in that Season. Plenty Per Root is 0 if a Season of Plenty did not occur.
 * @param internalTokenBalance A mapping from Farmer address to Token address to Internal Balance. It stores the amount of the Token that the Farmer has stored as an Internal Balance in Beanstalk.
 * @param unripeClaimed True if a Farmer has Claimed an Unripe Token. A mapping from Farmer to Unripe Token to its Claim status.
 * @param u Unripe Settings for a given Token address. The existence of a non-zero Unripe Settings implies that the token is an Unripe Token. The mapping is from Token address to Unripe Settings.
 * @param fertilizer A mapping from Fertilizer Id to the supply of Fertilizer for each Id.
 * @param nextFid A linked list of Fertilizer Ids ordered by Id number. Fertilizer Id is the Beans Per Fertilzer level at which the Fertilizer no longer receives Beans. Sort in order by which Fertilizer Id expires next.
 * @param activeFertilizer The number of active Fertilizer.
 * @param fertilizedIndex The total number of Fertilizer Beans.
 * @param unfertilizedIndex The total number of Unfertilized Beans ever.
 * @param fFirst The lowest active Fertilizer Id (start of linked list that is stored by nextFid). 
 * @param fLast The highest active Fertilizer Id (end of linked list that is stored by nextFid). 
 * @param bpf The cumulative Beans Per Fertilizer (bfp) minted over all Season.
 * @param vestingPeriodRoots the number of roots to add to the global roots, in the case the user plants in the morning. // placed here to save a storage slot.s
 * @param recapitalized The nubmer of USDC that has been recapitalized in the Barn Raise.
 * @param isFarm Stores whether the function is wrapped in the `farm` function (1 if not, 2 if it is).
 * @param ownerCandidate Stores a candidate address to transfer ownership to. The owner must claim the ownership transfer.
 * @param wellOracleSnapshots A mapping from Well Oracle address to the Well Oracle Snapshot.
 * @param beanEthPrice Stores the beanEthPrice during the sunrise() function. Returns 1 otherwise.
 * @param migratedBdvs Stores the total migrated BDV since the implementation of the migrated BDV counter. See {LibLegacyTokenSilo.incrementMigratedBdv} for more info.
 */
struct AppStorage {
    uint8 deprecated_index;
    int8[32] cases; 
    bool paused; // ────────┐ 1 
    uint128 pausedAt; // ───┘ 16 (17/32)
    Storage.Season season;
    Storage.Contracts c;
    Storage.Field f;
    Storage.Governance g;
    Storage.CurveMetapoolOracle co;
    Storage.Rain r;
    Storage.Silo s;
    uint256 reentrantStatus;
    Storage.Weather w;

    uint256 earnedBeans;
    uint256[14] deprecated;
    mapping (address => Account.State) a;
    uint32 deprecated_bip0Start; // ─────┐ 4
    uint32 deprecated_hotFix3Start; // ──┘ 4 (8/32)
    mapping (uint32 => Storage.Fundraiser) fundraisers;
    uint32 fundraiserIndex; // 4 (4/32)
    mapping (address => bool) deprecated_isBudget;
    mapping(uint256 => bytes32) podListings;
    mapping(bytes32 => uint256) podOrders;
    mapping(address => Storage.AssetSilo) siloBalances;
    mapping(address => Storage.SiloSettings) ss;
    uint256[2] deprecated2;
    uint128 newEarnedStalk; // ──────┐ 16
    uint128 vestingPeriodRoots; // ──┘ 16 (32/32)
    mapping (uint32 => uint256) sops;

    // Internal Balances
    mapping(address => mapping(IERC20 => uint256)) internalTokenBalance;

    // Unripe
    mapping(address => mapping(address => bool)) unripeClaimed;
    mapping(address => Storage.UnripeSettings) u;

    // Fertilizer
    mapping(uint128 => uint256) fertilizer;
    mapping(uint128 => uint128) nextFid;
    uint256 activeFertilizer;
    uint256 fertilizedIndex;
    uint256 unfertilizedIndex;
    uint128 fFirst;
    uint128 fLast;
    uint128 bpf;
    uint256 recapitalized;

    // Farm
    uint256 isFarm;

    // Ownership
    address ownerCandidate;

    // Well
    mapping(address => bytes) wellOracleSnapshots;
    uint256 beanEthPrice;

    // Silo V3 BDV Migration
    mapping(address => uint256) migratedBdvs;
}

File 7 of 23 : MetadataImage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;
import "../AppStorage.sol";
import {LibBytes64} from "contracts/libraries/LibBytes64.sol";
import {LibStrings} from "contracts/libraries/LibStrings.sol";
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {C} from "../../C.sol";


/**
 * @title MetadataImage
 * @author Brean
 * @notice Contains image metadata for ERC1155 deposits.
 * @dev fully on-chain generated SVG.
 */

contract MetadataImage {
    AppStorage internal s;

    using LibStrings for uint256;
    using LibStrings for int256;
    using SafeMath for uint256;

    string constant LEAF_COLOR_0 = '#A8C83A';
    string constant LEAF_COLOR_1 = '#89A62F';
    uint256 constant NUM_PLOTS = 21;
    uint256 constant STALK_GROWTH = 2e2;

    function imageURI(address token, int96 stem, int96 stemTip) public view returns (string memory) {
        return string(
            abi.encodePacked(
                "data:image/svg+xml;base64,", 
                LibBytes64.encode(bytes(generateImage(token, stem, stemTip)))
            )
        );
    }

    function generateImage(address token, int96 stem, int96 stemTip) internal pure returns (string memory) {
        int96 grownStalkPerBdv = stemTip - stem;
        return string(
            abi.encodePacked(
                '<svg class="svgBody" width="255" height="350" viewBox="0 0 255 350" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">',
                defs(grownStalkPerBdv),
                back(),
                printPlots(grownStalkPerBdv),
                blackBars(token, stem),
                '</svg>'
            )
        );
    }
    function back() internal pure returns(string memory) {
        return string(abi.encodePacked(
            '<rect width="255" height="350" rx="10" fill="',
            '#253326',
            '"/>'
        ));
    }
    function defs(int96 stemTip) internal pure returns(string memory) {
        (uint256 sprouts,) = getNumStemsAndPlots(stemTip);
        uint256 sproutsInFinalRow = sprouts.mod(4);
        return string(abi.encodePacked(
            '<defs>',
            plot(),
            fullLeafPlot(),
            emptyPlot(),
            partialLeafRow(sproutsInFinalRow),
            partialLeafPlot(stemTip),
            leaf(),
            silo(),
            beanToken(),
            bean3CRVToken(),
            urBeanToken(),
            beanETHCP2WellToken(),
            urBeanETHCP2WellToken(),
            fullLeafRow(),
            '</defs>'
        ));
    }

    function mask() internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<clipPath id="borderMask">',
            border(),
            '</clipPath>'
        ));
    }

    function border() internal pure returns (string memory) {
        return '<rect x="8" y="8" width="240" height="335" rx="6" stroke="#9BCAA0" stroke-width="2" fill="none"/>';
    }

    function fullLeafRow() internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<g id="leafRow">',
            '<use xlink:href="#leaf" x="0" y="0"/>',
            '<use xlink:href="#leaf" x="-12" y="-7"/>',
            '<use xlink:href="#leaf" x="-24" y="-14"/>',
            '<use xlink:href="#leaf" x="-36" y="-21"/>',
            '</g>'
        ));
    }

    function partialLeafRow(uint256 n) internal pure returns (string memory) {
        if (n == 0) { 
            return string(abi.encodePacked(
                '<g id="partialLeafRow">',
                '</g>'
            ));
        }
        if (n == 1) { 
            return string(abi.encodePacked(
                '<g id="partialLeafRow">',
                '<use xlink:href="#leaf" x="0" y="0"/>',
                '</g>'
            ));
        }
        if (n == 2) { 
            return string(abi.encodePacked(
                '<g id="partialLeafRow">',
                '<use xlink:href="#leaf" x="0" y="0"/>',
                '<use xlink:href="#leaf" x="-12" y="-7"/>',
                '</g>'
            ));
        }
        if (n == 3) { 
            return string(abi.encodePacked(
                '<g id="partialLeafRow">',
                '<use xlink:href="#leaf" x="0" y="0"/>',
                '<use xlink:href="#leaf" x="-12" y="-7"/>',
                '<use xlink:href="#leaf" x="-24" y="-14"/>',
                '</g>'
            ));
        } else {
            return string(abi.encodePacked(
                '<g id="partialLeafRow">',
                '<use xlink:href="#leaf" x="0" y="0"/>',
                '<use xlink:href="#leaf" x="-12" y="-7"/>',
                '<use xlink:href="#leaf" x="-24" y="-14"/>',
                '<use xlink:href="#leaf" x="-36" y="-21"/>',
                '</g>'
            ));
        }
       
    }


    function fullLeafPlot() internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<g id="fullLeafPlot">',
            useAssetTransform('plot',-35,0),
            useAssetTransformFill('leafRow',-35,0, LEAF_COLOR_0),
            useAssetTransformFill('leafRow',-47,7, LEAF_COLOR_1),
            useAssetTransformFill('leafRow',-60,14, LEAF_COLOR_0),
            useAssetTransformFill('leafRow',-73,21, LEAF_COLOR_1),
            '</g>'
        ));
    }

    function emptyPlot() internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<g id="emptyPlot">',
            useAssetTransform('plot',-35,0),
            '</g>'
        ));
    }

    function partialLeafPlot(int96 stalkPerBDV) internal pure returns (string memory _plot) {
        uint256 totalSprouts = uint256(stalkPerBDV).div(STALK_GROWTH).add(16);
        uint256 numRows = uint256(totalSprouts).div(4).mod(4);
        uint256 numSprouts = uint256(totalSprouts).mod(4);
        if (numRows == 0) {
            if (numSprouts > 0) {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    useAssetTransform('plot',-35,0),
                    useAssetTransformFill('partialLeafRow',-35,0, LEAF_COLOR_0),
                    '</g>'
                ));
            } else {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    threeLeafRows(),
                    useAssetTransformFill('leafRow',-73,21, LEAF_COLOR_1),
                    '</g>'
                ));
            }
        }
        if (numRows == 1) {
            if (numSprouts > 0) {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    oneLeafRow(),
                    useAssetTransformFill('partialLeafRow',-47,7, LEAF_COLOR_1),
                    '</g>'
                ));
            } else {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    oneLeafRow(),
                    '</g>'
                ));
            }
        }
        if (numRows == 2) {
            if (numSprouts > 0) {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    twoLeafRows(),
                    useAssetTransformFill('partialLeafRow',-60,14, LEAF_COLOR_0),
                    '</g>'
                ));
            } else {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    twoLeafRows(),
                    '</g>'
                ));
            }
            
        }
        if (numRows == 3) {
            if (numSprouts > 0) {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    threeLeafRows(),
                    useAssetTransformFill('partialLeafRow',-73,21, LEAF_COLOR_1),
                    '</g>'
                ));

            } else {
                _plot = string(abi.encodePacked(
                    '<g id="partialLeafPlot">',
                    threeLeafRows(),
                    '</g>'
                ));
            }
        }
    }

    function printPlots(int96 stalkPerBDV) internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<use xlink:href="#silo" x="99" y="55"/><g id="allPlot" clip-path="url(#borderMask)">',
                plotLogic(stalkPerBDV),
            '</g>'
        ));
    }

    function plotLogic(int96 stalkPerBDV) internal pure returns (string memory) {

        int256[2][21] memory XYPLOT = [

        [int256(-69),-164], // 20
        [int256(69),-164], // 19

        [int256(0),-124], // 13
        [int256(138),-124], // 18
        [int256(-138),-124], // 21

        [int256(-69),-84], // 14
        [int256(69),-84], // 12

        [int256(-138),-44], // 15
        [int256(0),-44], // 5
        [int256(138),-44], // 11

        [int256(-69),-4], // 6
        [int256(69),-4], // 4

        [int256(-138),36], // 7
        [int256(138),36], // 3

        [int256(-69),76], // 8 
        [int256(69),76], // 2

        [int256(-138),116], // 16
        [int256(0),116], // 1
        [int256(138),116], // 10
            
        [int256(69),156], // 9
        [int256(-69),156] // 17
        
        ];
        uint256[NUM_PLOTS] memory order = [uint256(20),19,13,18,21,14,12,15,5,11,6,4,7,3,8,2,16,1,10,9,17];

        bytes memory _plot;

        (, uint256 numPlotsToFill) = getNumStemsAndPlots(stalkPerBDV);
        
        // first plot should always be planted fully, and every 2% stalk adds a sprout to the next plot.
        for(uint256 i = 0; i < NUM_PLOTS; ++i) {
            uint256 plotNo = order[i];
            if (plotNo < numPlotsToFill) {
                _plot = abi.encodePacked(
                    _plot,
                    useAsset(
                        'fullLeafPlot',
                        XYPLOT[i][0],
                        XYPLOT[i][1]
                    )
                );
            } else if (plotNo == numPlotsToFill) {
                if (numPlotsToFill == 1) {
                    _plot = abi.encodePacked(
                    _plot,
                    useAsset(
                        'fullLeafPlot',
                        XYPLOT[i][0],
                        XYPLOT[i][1]
                    ));
                } else {
                    _plot = abi.encodePacked(
                    _plot,
                    useAsset(
                        'partialLeafPlot',
                        XYPLOT[i][0],
                        XYPLOT[i][1]
                    )
                );
                }
                
            } else {
                _plot = abi.encodePacked(
                    _plot,
                    useAsset(
                        'emptyPlot',
                        XYPLOT[i][0],
                        XYPLOT[i][1]
                    )
                );
            }
            if (i == 11) {
                _plot= abi.encodePacked(
                    _plot,
                    '<use xlink:href="#silo" x="47" y="55" transform="scale(1.7)"/>'
                );
            }
        }
        return string(_plot);
    }

    function useAsset(string memory assetName, int256 x, int256 y) internal pure returns (string memory) { 
        return string(abi.encodePacked(
            '<use xlink:href="#',
            assetName,
            '" x="',
            intToStr(x),
            '" y="',
            intToStr(y),
            '" />'
        ));
    }

    function useAssetFill(string memory assetName, int256 x, int256 y, string memory color) internal pure returns (string memory) { 
        return string(abi.encodePacked(
            '<use xlink:href="#',
            assetName,
            '" x="',
            intToStr(x),
            '" y="',
            intToStr(y),
            '" fill="',
            color,
            '" />'
        ));
    }

    function plot() internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                '<g id="plot">',
                '<path d="M79.5728 129.265L127.469 156.833L175.443 129.245L127.469 101.697L79.5728 129.265Z" fill="#944A27"/>',
                '<path d="M79.5332 133.426L79.5727 129.265L127.469 156.833L127.507 160.908L79.5332 133.426Z" fill="#75391F"/>',
                '<path d="M175.467 133.4L175.443 129.245L127.469 156.833L127.507 160.908L175.467 133.4Z" fill="#67331E"/>',
                "</g>"
            )
        );
    }

    function leaf() internal pure returns (string memory) { 
        return string(
            abi.encodePacked(
                '<g id="leaf">',
                '<path d="M171.884 118.983a4.932 4.932 0 0 1-1.018 2.606 4.715 4.715 0 0 1-1.878 1.439c-.465.195-1.735.727-2.364.176-.246 3.298-1.593 6.512-2.253 7.954a4.532 4.532 0 0 1-.313-.933c-.211-.975-.038-1.763.078-2.295.202-.921.353-1.612.467-2.14-1.177.694-2.642.569-3.558-.272-.796-.732-1.083-1.921-.743-3.034.498.011 1.939.109 3.247 1.167a5.13 5.13 0 0 1 1.21 1.413c.159-.74.199-.958.238-1.179.209-1.213.322-1.872.274-2.724a7.73 7.73 0 0 0-.908-3.177c-.772.415-1.789.196-2.378-.304-.339-.287-.556-.682-.764-1.692a12.739 12.739 0 0 1-.176-3.909c.789.603 1.47 1.019 1.937 1.283.944.536 1.344.639 1.761 1.167.152.193.649.842.586 1.751-.011.172-.053.795-.464 1.293a6.83 6.83 0 0 1 1.384 2.227c.14.368.242.744.311 1.15.107-.207.261-.439.511-.722.453-.513.87-.992 1.604-1.284.683-.272 1.28-.249 1.723-.234a5.302 5.302 0 0 1 1.486.273Z"/>',
                '</g>'
            )
        );
    }

    function silo() internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                '<g id="silo">',
                '<path d="M57.108 71.29c.188-11.653-12.01-21.303-27.243-21.552-15.234-.25-27.736 8.995-27.923 20.649-.187 11.654 12.01 21.304 27.244 21.553 15.233.25 27.735-8.995 27.922-20.65Z" fill="#666"/>',
                '<path d="M.464 19.544c.699 16.585 1.4 33.169 2.098 49.752.021 2.381.48 4.278.883 5.539.277.86.741 2.275 1.778 3.867.494.759 1.212 1.7 3.002 3.332 1.739 1.586 3.35 3.056 5.732 4.398 3.293 1.855 6.151 2.396 8.791 2.896 1.855.35 5.149.948 9.488.556a32.707 32.707 0 0 0 9.315-2.287c1.862-.759 4.642-1.917 7.633-4.4 1.348-1.12 3.448-2.897 5.197-5.95a20.114 20.114 0 0 0 2.25-5.998c.21-17.552.42-35.104.632-52.657l-56.8.952h.001Z" fill="#B3B3B3"/>',
                '<path d="M57.48 19.482C57.645 9.24 44.978.727 29.187.468 13.397.21.463 8.303.298 18.546.134 28.788 12.8 37.3 28.591 37.56c15.79.258 28.724-7.835 28.889-18.078Z" fill="#CCC"/>',
                '<path d="M30.314 7.137c.009-.561-.68-1.028-1.538-1.042-.859-.014-1.562.43-1.571.991-.01.562.68 1.028 1.538 1.042.859.015 1.562-.43 1.57-.99Z" fill="#666"/>',
                '<path d="M6.414 28.89a15.777 15.777 0 0 1-2.093-2.146c-.856-1.063-2.453-3.093-2.975-6.112a11.765 11.765 0 0 1-.093-3.307l25.43-9.976c.043.142.188.555.604.868.46.346.947.34 1.086.334L6.413 28.888v.002Z" fill="#E6E6E6"/>',
                '<path opacity=".33" d="M1.477 16.029c.25-.931.706-2.258 1.57-3.695.655-1.092 1.292-1.825 1.76-2.358.584-.665 1.776-1.934 3.679-3.29 2.953-2.105 5.696-3.05 7.723-3.73a37.35 37.35 0 0 1 6.485-1.547l5.242 4.316a1.48 1.48 0 0 0-1.214.967L1.48 16.03h-.002Z" fill="#999"/>',
                '<path opacity=".44" d="M1.81 26.532c.206.494.484 1.05.86 1.63a10.266 10.266 0 0 0 2.278 2.486L6.552 78.22a17.272 17.272 0 0 1-3-7.413L1.81 26.532Z" fill="#E6E6E6"/>',
                '<path d="m33.092 49.441-6.381 15.211s-6.078-11.159 6.381-15.21Z" fill="#8E8E8E"/>',
                '<path d="m26.725 64.858-.091-.175c-.026-.049-2.634-4.923-.867-9.37 1.057-2.717 3.518-4.725 7.3-5.946l.187-.061-6.53 15.552Zm6.212-15.268c-3.621 1.217-5.991 3.168-7.022 5.798-1.538 3.908.355 8.166.788 9.054l6.234-14.852ZM28.093 63.737l4.484-10.87s7.365 6.337-4.484 10.87Z" fill="#8E8E8E"/>'
                "</g>"
            )
        );
    }

    function beanToken() internal pure returns (string memory) {
        return beanTemplateToken(false);
    }

    function urBeanToken() internal pure returns (string memory) {
        return beanTemplateToken(true);
    }

    function beanETHCP2WellToken() internal pure returns (string memory) {
        return beanETHCP2WellTemplateToken(false);
    }

    function urBeanETHCP2WellToken() internal pure returns (string memory) {
        return beanETHCP2WellTemplateToken(true);
    }

    function bean3CRVToken() internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<g id="BEAN3CRV',
            '"><rect y=".5" width="12" height="12" rx="6" fill="#46B955',
            '"/><path d="m7.687 1.764-3.504 9.36S.298 4.499 7.687 1.765Z" fill="#fff"/>',
            '<path d="M8.132 8.078c-.466.64-1.297 1.323-2.695 1.992l2.126-5.777c.089.09.193.204.3.338.303.375.625.891.744 1.484.117.583.04 1.253-.475 1.963Z" fill="url(#a)" stroke="#fff" stroke-width=".5"/>',
            '<defs><linearGradient id="a" x1="6.95" y1="3.853" x2="6.95" y2="10.544" gradientUnits="userSpaceOnUse">',
            '<stop stop-color="#820202"/><stop offset=".182" stop-color="#F71E05"/>',
            '<stop offset=".516" stop-color="#F0F507"/><stop offset=".734" stop-color="#85CD75"/><stop offset="1" stop-color="#029DFB"/>',
            '</linearGradient></defs>',
            '</g>'
            )
        );
    }

    function beanTemplateToken(bool ripe) internal pure returns (string memory) {
        return string(abi.encodePacked( 
            '<g id="',
            ripe ? 'urBEAN' : 'BEAN',
            '"><rect width="12" height="12" rx="6" fill="',
            ripe ? '#7F5533' : '#46B955',
            '"/><path d="m7.687 1.265-3.504 9.36S.298 3.999 7.687 1.266Zm-2.691 8.78 2.462-6.691s4.538 3.67-2.462 6.691Z" fill="#fff"/>',
            '</g>'
            )
        );
    }

    function beanETHCP2WellTemplateToken(bool ripe) internal pure returns (string memory) {
        return string(abi.encodePacked(
            '<g id="',
            ripe ? 'urBEANETH' : 'BEANETH',
            '"><rect width="12" height="12" rx="6" fill="',
            ripe ? '#7F5533' : '#46B955',
            '"/><path d="m7.684 1.265-3.505 9.36c.003 0-3.884-6.625 3.505-9.36Z" fill="#fff"/>',   
            '<path d="M8.952 6.986a.063.063 0 0 1-.022.003c-.71.13-1.424.255-2.134.381-.281.052-.565.103-.846.152a.036.036 0 0 1-.026 0l2.14-5.625.004-.003c.297 1.702.59 3.394.884 5.092Zm-.187.478c-1.266.859-2.531 1.721-3.8 2.58l.781-2.054c.007.004.013 0 .023 0 .759-.132 1.514-.268 2.27-.4l.697-.126.03-.006c-.004.003 0 .006 0 .006Z" fill="#000"/>',
            '</g>'
            )
        );
    }

    function useAssetTransform(string memory assetName, int256 x, int256 y) internal pure returns (string memory) { 
        return string(abi.encodePacked(
            '<use xlink:href="#',
            assetName,
            '" x="',
            intToStr(x),
            '" y="',
            intToStr(y),
            '" transform="scale(1.4)"/>'
        ));
    }

    function useAssetTransformFill(string memory assetName, int256 x, int256 y, string memory color) internal pure returns (string memory) { 
        return string(abi.encodePacked(
            '<use xlink:href="#',
            assetName,
            '" x="',
            intToStr(x),
            '" y="',
            intToStr(y),
            '" fill="',
            color,
            '" transform="scale(1.4)"/>'
        ));
    }

    function threeLeafRows() internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                twoLeafRows(),
                useAssetTransformFill('leafRow',-60,14, LEAF_COLOR_0)
            )
        );
    }

    function twoLeafRows() internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                oneLeafRow(),
                useAssetTransformFill('leafRow',-47,7, LEAF_COLOR_1)
            )
        );
    }

    function oneLeafRow() internal pure returns(string memory) {
        return string(
            abi.encodePacked(
                useAssetTransform('plot',-35,0),
                useAssetTransformFill('leafRow',-35,0, LEAF_COLOR_0)
            )
        );
    }

    

    function blackBars(address token, int96 stem) internal pure returns(string memory) {
        return string(
            abi.encodePacked(
                '<rect x="0" y="0" width="255" height="20" rx="5" fill="#242424"/>',
                tokenName(token),
                useAsset(getTokenName(token), 240, 4),
                '<rect x="0" y="330" width="255" height="20" rx="5" fill="#242424"/>',
                movingTokenAddress(token),
                '<text x="235" y="14.5" font-size="12" fill="White" text-anchor="end" font-family="futura">Stem: ',
                sciNotation(stem),
                '</text>'
            )
        );
    }

    function sciNotation(int96 stem) internal pure returns (string memory) {
        if (stem >= 0) {
            // if stem is greater than 1e5, use scientific notation
            if (stem > 100_000) {
                return powerOfTen(uint256(stem));
            } else {
                return uint256(stem).toString();
            }
        } else {
            // if stem is less than -1e5, use scientific notation
            if (-stem > 100_000) {
                return string(abi.encodePacked("-", powerOfTen(uint256(-stem))));
            } else {
                return int256(stem).toString();
            }
        }
    }

    function powerOfTen(uint256 stem) internal pure returns (string memory) {
        // if else ladder to determine how many digits to show.
        if (stem < 1e6) {
            return stemDecimals(stem, 5);
        } else if (stem < 1e7) {
            return stemDecimals(stem, 6);
        } else if (stem < 1e8) {
            return stemDecimals(stem, 7);
        } else if (stem < 1e9) {
            return stemDecimals(stem, 8);
        } else if (stem < 1e10) {
            return stemDecimals(stem, 9);
        } else if (stem < 1e11) {
            return stemDecimals(stem, 10);
        } else if (stem < 1e12) {
            return stemDecimals(stem, 11);
        } else if (stem < 1e13) {
            return stemDecimals(stem, 12);
        } else if (stem < 1e14) {
            return stemDecimals(stem, 13);
        } else if (stem < 1e15) {
            return stemDecimals(stem, 14);
        } else if (stem < 1e16) {
            return stemDecimals(stem, 15);
        } else if (stem < 1e17) {
            return stemDecimals(stem, 16);
        } else if (stem < 1e18) {
            return stemDecimals(stem, 17);
        } else if (stem < 1e19) {
            return stemDecimals(stem, 18);
        } else if (stem < 1e20) {
            return stemDecimals(stem, 19);
        } else if (stem < 1e21) {
            return stemDecimals(stem, 20);
        } else if (stem < 1e22) {
            return stemDecimals(stem, 21);
        } else if (stem < 1e23) {
            return stemDecimals(stem, 22);
        } else if (stem < 1e24) {
            return stemDecimals(stem, 23);
        } else if (stem < 1e25) {
            return stemDecimals(stem, 24);
        } else if (stem < 1e26) {
            return stemDecimals(stem, 25);
        } else if (stem < 1e27) {
            return stemDecimals(stem, 26);
        } else if (stem < 1e28) {
            return stemDecimals(stem, 27);
        } else {
            return stemDecimals(stem, 28);
        }
    }
    
    function stemDecimals(uint256 stem, uint256 exponent) internal pure returns (string memory) {
        return string(abi.encodePacked(
            stem.div(10 ** exponent).toString(),
            '.',
            stem.div(10 ** exponent.sub(5)).mod(1e5).toString(),
            'e',
            exponent.toString()
        ));
    }

    function tokenName(address token) internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                '<text x="10" y="14.5" font-size="12" fill="White" text-anchor="start" font-family="futura">',
                getTokenName(token),
                ' Deposit</text>'
            )
        );
    }

    function movingTokenAddress(address token) internal pure returns (string memory) {
        return string(
            abi.encodePacked(
                '<text x="127" y="343" font-size="10" fill="White" text-anchor="middle" font-family="futura">',
                '<tspan><animate attributeName="x" from="375" to="50" dur="10s" repeatCount="indefinite" />',
                LibStrings.toHexString(token),
                '</tspan></text>',
                '<text x="127" y="343" font-size="10" fill="White" text-anchor="middle" font-family="futura">',
                '<tspan><animate attributeName="x" from="50" to="-275" dur="10s" repeatCount="indefinite" />',
                LibStrings.toHexString(token),
                '</tspan></text>'
            )
        );
    }

    function intToStr(int256 x) internal pure returns (string memory) {
        if (x < 0) {
            return string(abi.encodePacked(
                '-',
                uint256(-x).toString()
            ));
        } else {
            return uint256(x).toString();
        }        
    }

    function getTokenName(address token) internal pure returns (string memory tokenString) {
        if (token == C.BEAN) {
            tokenString = "BEAN";
        }
        else if (token == C.CURVE_BEAN_METAPOOL) {
            tokenString = "BEAN3CRV";
        }
        else if (token == C.UNRIPE_BEAN) {
            tokenString = "urBEAN";
        }
        else if (token == C.UNRIPE_LP) {
            tokenString = "urBEANETH";
        }
        else if (token == C.BEAN_ETH_WELL) {
            tokenString = "BEANETH";
        } else {
            revert("token not whitelisted.");
        }
    }

    function getNumStemsAndPlots(int96 grownStalkPerBDV) 
        internal 
        pure 
        returns (uint256 numStems, uint256 plots)
    {
        // 1 sprout on the image is equal to 0.02 stalk
        numStems = uint256(grownStalkPerBDV).div(STALK_GROWTH);
        plots = numStems.div(16).add(1);
        if (numStems.mod(16) > 0) plots = plots.add(1);
    }
}

File 8 of 23 : C.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "./interfaces/IBean.sol";
import "./interfaces/ICurve.sol";
import "./interfaces/IFertilizer.sol";
import "./interfaces/IProxyAdmin.sol";
import "./libraries/Decimal.sol";

/**
 * @title C
 * @author Publius
 * @notice Contains constants used throughout Beanstalk.
 */
library C {
    using Decimal for Decimal.D256;
    using SafeMath for uint256;

    //////////////////// Globals ////////////////////

    uint256 internal constant PRECISION = 1e18;
    uint256 private constant CHAIN_ID = 1;
    bytes constant BYTES_ZERO = new bytes(0);

    /// @dev The block time for the chain in seconds.
    uint256 internal constant BLOCK_LENGTH_SECONDS = 12;

    //////////////////// Season ////////////////////

    /// @dev The length of a Season meaured in seconds.
    uint256 private constant CURRENT_SEASON_PERIOD = 3600; // 1 hour
    uint256 internal constant SOP_PRECISION = 1e24;

    //////////////////// Silo ////////////////////

    uint256 internal constant SEEDS_PER_BEAN = 2;
    uint256 internal constant STALK_PER_BEAN = 10000;
    uint256 private constant ROOTS_BASE = 1e12;

    //////////////////// Exploit Migration ////////////////////

    uint256 private constant UNRIPE_LP_PER_DOLLAR = 1884592; // 145_113_507_403_282 / 77_000_000
    uint256 private constant ADD_LP_RATIO = 866616;
    uint256 private constant INITIAL_HAIRCUT = 185564685220298701;

    //////////////////// Contracts ////////////////////

    address internal constant BEAN = 0xBEA0000029AD1c77D3d5D23Ba2D8893dB9d1Efab;
    address internal constant CURVE_BEAN_METAPOOL = 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49;

    address internal constant UNRIPE_BEAN = 0x1BEA0050E63e05FBb5D8BA2f10cf5800B6224449;
    address internal constant UNRIPE_LP = 0x1BEA3CcD22F4EBd3d37d731BA31Eeca95713716D;

    address private constant CURVE_3_POOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
    address private constant THREE_CRV = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490;

    address private constant FERTILIZER = 0x402c84De2Ce49aF88f5e2eF3710ff89bFED36cB6;
    address private constant FERTILIZER_ADMIN = 0xfECB01359263C12Aa9eD838F878A596F0064aa6e;

    address private constant TRI_CRYPTO = 0xc4AD29ba4B3c580e6D59105FFf484999997675Ff;
    address private constant TRI_CRYPTO_POOL = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
    address private constant CURVE_ZAP = 0xA79828DF1850E8a3A3064576f380D90aECDD3359;

    address private constant UNRIPE_CURVE_BEAN_LUSD_POOL = 0xD652c40fBb3f06d6B58Cb9aa9CFF063eE63d465D;
    address private constant UNRIPE_CURVE_BEAN_METAPOOL = 0x3a70DfA7d2262988064A2D051dd47521E43c9BdD;

    address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
    address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address internal constant UNIV3_ETH_USDC_POOL = 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640; // 0.05% pool
    address internal constant UNIV3_ETH_USDT_POOL = 0x11b815efB8f581194ae79006d24E0d814B7697F6; // 0.05% pool

    // Use external contract for block.basefee as to avoid upgrading existing contracts to solidity v8
    address private constant BASE_FEE_CONTRACT = 0x84292919cB64b590C0131550483707E43Ef223aC;

    //////////////////// Well ////////////////////

    uint256 internal constant WELL_MINIMUM_BEAN_BALANCE = 1000_000_000; // 1,000 Beans
    address internal constant BEANSTALK_PUMP = 0xBA510f10E3095B83a0F33aa9ad2544E22570a87C;
    address internal constant BEAN_ETH_WELL = 0xBEA0e11282e2bB5893bEcE110cF199501e872bAd;

    function getSeasonPeriod() internal pure returns (uint256) {
        return CURRENT_SEASON_PERIOD;
    }

    function getBlockLengthSeconds() internal pure returns (uint256) {
        return BLOCK_LENGTH_SECONDS;
    }

    function getChainId() internal pure returns (uint256) {
        return CHAIN_ID;
    }

    function getSeedsPerBean() internal pure returns (uint256) {
        return SEEDS_PER_BEAN;
    }

    function getStalkPerBean() internal pure returns (uint256) {
      return STALK_PER_BEAN;
    }

    function getRootsBase() internal pure returns (uint256) {
        return ROOTS_BASE;
    }

    /**
     * @dev The pre-exploit BEAN:3CRV Curve metapool address.
     */
    function unripeLPPool1() internal pure returns (address) {
        return UNRIPE_CURVE_BEAN_METAPOOL;
    }

    /**
     * @dev The pre-exploit BEAN:LUSD Curve plain pool address.
     */
    function unripeLPPool2() internal pure returns (address) {
        return UNRIPE_CURVE_BEAN_LUSD_POOL;
    }

    function unripeBean() internal pure returns (IERC20) {
        return IERC20(UNRIPE_BEAN);
    }

    function unripeLP() internal pure returns (IERC20) {
        return IERC20(UNRIPE_LP);
    }

    function bean() internal pure returns (IBean) {
        return IBean(BEAN);
    }

    function usdc() internal pure returns (IERC20) {
        return IERC20(USDC);
    }

    function curveMetapool() internal pure returns (ICurvePool) {
        return ICurvePool(CURVE_BEAN_METAPOOL);
    }

    function curve3Pool() internal pure returns (I3Curve) {
        return I3Curve(CURVE_3_POOL);
    }
    
    function curveZap() internal pure returns (ICurveZap) {
        return ICurveZap(CURVE_ZAP);
    }

    function curveZapAddress() internal pure returns (address) {
        return CURVE_ZAP;
    }

    function curve3PoolAddress() internal pure returns (address) {
        return CURVE_3_POOL;
    }

    function threeCrv() internal pure returns (IERC20) {
        return IERC20(THREE_CRV);
    }

    function UniV3EthUsdc() internal pure returns (address){
        return UNIV3_ETH_USDC_POOL;
    }

    function fertilizer() internal pure returns (IFertilizer) {
        return IFertilizer(FERTILIZER);
    }

    function fertilizerAddress() internal pure returns (address) {
        return FERTILIZER;
    }

    function fertilizerAdmin() internal pure returns (IProxyAdmin) {
        return IProxyAdmin(FERTILIZER_ADMIN);
    }

    function triCryptoPoolAddress() internal pure returns (address) {
        return TRI_CRYPTO_POOL;
    }

    function triCrypto() internal pure returns (IERC20) {
        return IERC20(TRI_CRYPTO);
    }

    function unripeLPPerDollar() internal pure returns (uint256) {
        return UNRIPE_LP_PER_DOLLAR;
    }

    function dollarPerUnripeLP() internal pure returns (uint256) {
        return 1e12/UNRIPE_LP_PER_DOLLAR;
    }

    function exploitAddLPRatio() internal pure returns (uint256) {
        return ADD_LP_RATIO;
    }

    function precision() internal pure returns (uint256) {
        return PRECISION;
    }

    function initialRecap() internal pure returns (uint256) {
        return INITIAL_HAIRCUT;
    }

}

File 9 of 23 : IBean.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title IBean
 * @author Publius
 * @notice Bean Interface
 */
abstract contract IBean is IERC20 {
    function burn(uint256 amount) public virtual;
    function burnFrom(address account, uint256 amount) public virtual;
    function mint(address account, uint256 amount) public virtual;
    function symbol() public view virtual returns (string memory);
}

File 10 of 23 : ICurve.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;

interface ICurvePool {
    function A_precise() external view returns (uint256);
    function get_balances() external view returns (uint256[2] memory);
    function totalSupply() external view returns (uint256);
    function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount) external returns (uint256);
    function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount) external returns (uint256);
    function balances(int128 i) external view returns (uint256);
    function fee() external view returns (uint256);
    function coins(uint256 i) external view returns (address);
    function get_virtual_price() external view returns (uint256);
    function calc_token_amount(uint256[2] calldata amounts, bool deposit) external view returns (uint256);
    function calc_withdraw_one_coin(uint256 _token_amount, int128 i) external view returns (uint256);
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256);
    function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

interface ICurveZap {
    function add_liquidity(address _pool, uint256[4] memory _deposit_amounts, uint256 _min_mint_amount) external returns (uint256);
    function calc_token_amount(address _pool, uint256[4] memory _amounts, bool _is_deposit) external returns (uint256);
}

interface ICurvePoolR {
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy, address receiver) external returns (uint256);
    function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy, address receiver) external returns (uint256);
    function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount, address receiver) external returns (uint256);
}

interface ICurvePool2R {
    function add_liquidity(uint256[2] memory amounts, uint256 min_mint_amount, address reciever) external returns (uint256);
    function remove_liquidity(uint256 _burn_amount, uint256[2] memory _min_amounts, address reciever) external returns (uint256[2] calldata);
    function remove_liquidity_imbalance(uint256[2] memory _amounts, uint256 _max_burn_amount, address reciever) external returns (uint256);
}

interface ICurvePool3R {
    function add_liquidity(uint256[3] memory amounts, uint256 min_mint_amount, address reciever) external returns (uint256);
    function remove_liquidity(uint256 _burn_amount, uint256[3] memory _min_amounts, address reciever) external returns (uint256[3] calldata);
    function remove_liquidity_imbalance(uint256[3] memory _amounts, uint256 _max_burn_amount, address reciever) external returns (uint256);
}

interface ICurvePool4R {
    function add_liquidity(uint256[4] memory amounts, uint256 min_mint_amount, address reciever) external returns (uint256);
    function remove_liquidity(uint256 _burn_amount, uint256[4] memory _min_amounts, address reciever) external returns (uint256[4] calldata);
    function remove_liquidity_imbalance(uint256[4] memory _amounts, uint256 _max_burn_amount, address reciever) external returns (uint256);
}

interface I3Curve {
    function get_virtual_price() external view returns (uint256);
}

interface ICurveFactory {
    function get_coins(address _pool) external view returns (address[4] calldata);
    function get_underlying_coins(address _pool) external view returns (address[8] calldata);
}

interface ICurveCryptoFactory {
    function get_coins(address _pool) external view returns (address[8] calldata);
}

interface ICurvePoolC {
    function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external returns (uint256);
}

interface ICurvePoolNoReturn {
    function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external;
    function add_liquidity(uint256[3] memory amounts, uint256 min_mint_amount) external;
    function remove_liquidity(uint256 _burn_amount, uint256[3] memory _min_amounts) external;
    function remove_liquidity_imbalance(uint256[3] memory _amounts, uint256 _max_burn_amount) external;
    function remove_liquidity_one_coin(uint256 _token_amount, uint256 i, uint256 min_amount) external;
}

interface ICurvePoolNoReturn128 {
    function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
    function remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount) external;
}

File 11 of 23 : IDiamondCut.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
/******************************************************************************/

interface IDiamondCut {
    enum FacetCutAction {Add, Replace, Remove}

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

File 12 of 23 : IFertilizer.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;

interface IFertilizer {
    struct Balance {
        uint128 amount;
        uint128 lastBpf;
    }
    function beanstalkUpdate(
        address account,
        uint256[] memory ids,
        uint128 bpf
    ) external returns (uint256);
    function beanstalkMint(address account, uint256 id, uint128 amount, uint128 bpf) external;
    function balanceOfFertilized(address account, uint256[] memory ids) external view returns (uint256);
    function balanceOfUnfertilized(address account, uint256[] memory ids) external view returns (uint256);
    function lastBalanceOf(address account, uint256 id) external view returns (Balance memory);
    function lastBalanceOfBatch(address[] memory account, uint256[] memory id) external view returns (Balance[] memory);
    function setURI(string calldata newuri) external;
}

File 13 of 23 : IProxyAdmin.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;
interface IProxyAdmin {
    function upgrade(address proxy, address implementation) external;
}

File 14 of 23 : Decimal.sol
/*
 SPDX-License-Identifier: MIT
*/

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";

/**
 * @title Decimal
 * @author dYdX
 *
 * Library that defines a fixed-point number with 18 decimal places.
 */
library Decimal {
    using SafeMath for uint256;

    // ============ Constants ============

    uint256 constant BASE = 10**18;

    // ============ Structs ============


    struct D256 {
        uint256 value;
    }

    // ============ Static Functions ============

    function zero()
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: 0 });
    }

    function one()
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: BASE });
    }

    function from(
        uint256 a
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: a.mul(BASE) });
    }

    function ratio(
        uint256 a,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: getPartial(a, BASE, b) });
    }

    // ============ Self Functions ============

    function add(
        D256 memory self,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.add(b.mul(BASE)) });
    }

    function sub(
        D256 memory self,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.sub(b.mul(BASE)) });
    }

    function sub(
        D256 memory self,
        uint256 b,
        string memory reason
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.sub(b.mul(BASE), reason) });
    }

    function mul(
        D256 memory self,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.mul(b) });
    }

    function div(
        D256 memory self,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.div(b) });
    }

    function pow(
        D256 memory self,
        uint256 b
    )
    internal
    pure
    returns (D256 memory)
    {
        if (b == 0) {
            return one();
        }

        D256 memory temp = D256({ value: self.value });
        for (uint256 i = 1; i < b; ++i) {
            temp = mul(temp, self);
        }

        return temp;
    }

    function add(
        D256 memory self,
        D256 memory b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.add(b.value) });
    }

    function sub(
        D256 memory self,
        D256 memory b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.sub(b.value) });
    }

    function sub(
        D256 memory self,
        D256 memory b,
        string memory reason
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: self.value.sub(b.value, reason) });
    }

    function mul(
        D256 memory self,
        D256 memory b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: getPartial(self.value, b.value, BASE) });
    }

    function div(
        D256 memory self,
        D256 memory b
    )
    internal
    pure
    returns (D256 memory)
    {
        return D256({ value: getPartial(self.value, BASE, b.value) });
    }

    function equals(D256 memory self, D256 memory b) internal pure returns (bool) {
        return self.value == b.value;
    }

    function greaterThan(D256 memory self, D256 memory b) internal pure returns (bool) {
        return compareTo(self, b) == 2;
    }

    function lessThan(D256 memory self, D256 memory b) internal pure returns (bool) {
        return compareTo(self, b) == 0;
    }

    function greaterThanOrEqualTo(D256 memory self, D256 memory b) internal pure returns (bool) {
        return compareTo(self, b) > 0;
    }

    function lessThanOrEqualTo(D256 memory self, D256 memory b) internal pure returns (bool) {
        return compareTo(self, b) < 2;
    }

    function isZero(D256 memory self) internal pure returns (bool) {
        return self.value == 0;
    }

    function asUint256(D256 memory self) internal pure returns (uint256) {
        return self.value.div(BASE);
    }

    // ============ Core Methods ============

    function getPartial(
        uint256 target,
        uint256 numerator,
        uint256 denominator
    )
    private
    pure
    returns (uint256)
    {
        return target.mul(numerator).div(denominator);
    }

    function compareTo(
        D256 memory a,
        D256 memory b
    )
    private
    pure
    returns (uint256)
    {
        if (a.value == b.value) {
            return 1;
        }
        return a.value > b.value ? 2 : 0;
    }
}

File 15 of 23 : LibAppStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

// Import all of AppStorage to give importers of LibAppStorage access to {Account}, etc.
import "../beanstalk/AppStorage.sol";

/**
 * @title LibAppStorage 
 * @author Publius
 * @notice Allows libaries to access Beanstalk's state.
 */
library LibAppStorage {
    function diamondStorage() internal pure returns (AppStorage storage ds) {
        assembly {
            ds.slot := 0
        }
    }
}

File 16 of 23 : LibBytes.sol
/**
 * SPDX-License-Identifier: MIT
 **/
 
pragma solidity =0.7.6;

/* 
* @author: Malteasy
* @title: LibBytes
*/

library LibBytes {

    /*
    * @notice From Solidity Bytes Arrays Utils
    * @author Gonçalo Sá <[email protected]>
    */
    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_start + 1 >= _start, "toUint8_overflow");
        require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    /*
    * @notice From Solidity Bytes Arrays Utils
    * @author Gonçalo Sá <[email protected]>
    */
    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_start + 4 >= _start, "toUint32_overflow");
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    /*
    * @notice From Solidity Bytes Arrays Utils
    * @author Gonçalo Sá <[email protected]>
    */
    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_start + 32 >= _start, "toUint256_overflow");
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    /**
    * @notice Loads a slice of a calldata bytes array into memory
    * @param b The calldata bytes array to load from
    * @param start The start of the slice
    * @param length The length of the slice
    */
    function sliceToMemory(bytes calldata b, uint256 start, uint256 length) internal pure returns (bytes memory) {
        bytes memory memBytes = new bytes(length);
        for(uint256 i = 0; i < length; ++i) {
            memBytes[i] = b[start + i];
        }
        return memBytes;
    }

    function packAddressAndStem(address _address, int96 stem) internal pure returns (uint256) {
        return uint256(_address) << 96 | uint96(stem);
    }

    function unpackAddressAndStem(uint256 data) internal pure returns(address, int96) {
        return (address(uint160(data >> 96)), int96(int256(data)));
    }


}

File 17 of 23 : LibBytes64.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;

/**
 * @author Brean
 * @dev Provides a set of functions to operate with Base64 strings.
 * @title Base64 is a 0.7.6 variation of Open Zeppelin's Base64.
 *
 */
library LibBytes64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 32)

            // Run over the input, 3 bytes at a time
            for {
                let dataPtr := data
                let endPtr := add(data, mload(data))
            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

File 18 of 23 : LibSafeMath128.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @author Publius
 * @title LibSafeMath128 is a uint128 variation of Open Zeppelin's Safe Math library.
**/
library LibSafeMath128 {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint128 a, uint128 b) internal pure returns (bool, uint128) {
        uint128 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint128 a, uint128 b) internal pure returns (bool, uint128) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint128 a, uint128 b) internal pure returns (bool, uint128) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint128 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint128 a, uint128 b) internal pure returns (bool, uint128) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint128 a, uint128 b) internal pure returns (bool, uint128) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint128 a, uint128 b) internal pure returns (uint128) {
        uint128 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint128 a, uint128 b) internal pure returns (uint128) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint128 a, uint128 b) internal pure returns (uint128) {
        if (a == 0) return 0;
        uint128 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint128 a, uint128 b) internal pure returns (uint128) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint128 a, uint128 b) internal pure returns (uint128) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint128 a, uint128 b, string memory errorMessage) internal pure returns (uint128) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 19 of 23 : LibSafeMath32.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @author Publius
 * @title LibSafeMath32 is a uint32 variation of Open Zeppelin's Safe Math library.
**/
library LibSafeMath32 {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint32 a, uint32 b) internal pure returns (bool, uint32) {
        uint32 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint32 a, uint32 b) internal pure returns (bool, uint32) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint32 a, uint32 b) internal pure returns (bool, uint32) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint32 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint32 a, uint32 b) internal pure returns (bool, uint32) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint32 a, uint32 b) internal pure returns (bool, uint32) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint32 a, uint32 b) internal pure returns (uint32) {
        uint32 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint32 a, uint32 b) internal pure returns (uint32) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint32 a, uint32 b) internal pure returns (uint32) {
        if (a == 0) return 0;
        uint32 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint32 a, uint32 b) internal pure returns (uint32) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint32 a, uint32 b) internal pure returns (uint32) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint32 a, uint32 b, string memory errorMessage) internal pure returns (uint32) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 20 of 23 : LibSafeMathSigned128.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library LibSafeMathSigned128 {
    int128 constant private _INT128_MIN = -2**127;

    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int128 a, int128 b) internal pure returns (int128) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT128_MIN), "SignedSafeMath: multiplication overflow");

        int128 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int128 a, int128 b) internal pure returns (int128) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT128_MIN), "SignedSafeMath: division overflow");

        int128 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int128 a, int128 b) internal pure returns (int128) {
        int128 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int128 a, int128 b) internal pure returns (int128) {
        int128 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

File 21 of 23 : LibSafeMathSigned96.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @title SignedSafeMath
 * @dev Signed math operations with safety checks that revert on error.
 */
library LibSafeMathSigned96 {
    int96 constant private _INT96_MIN = -2**95;

    /**
     * @dev Returns the multiplication of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(int96 a, int96 b) internal pure returns (int96) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        require(!(a == -1 && b == _INT96_MIN), "SignedSafeMath: multiplication overflow");

        int96 c = a * b;
        require(c / a == b, "SignedSafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two signed integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(int96 a, int96 b) internal pure returns (int96) {
        require(b != 0, "SignedSafeMath: division by zero");
        require(!(b == -1 && a == _INT96_MIN), "SignedSafeMath: division overflow");

        int96 c = a / b;

        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(int96 a, int96 b) internal pure returns (int96) {
        int96 c = a - b;
        require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");

        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(int96 a, int96 b) internal pure returns (int96) {
        int96 c = a + b;
        require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");

        return c;
    }
}

File 22 of 23 : LibStrings.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev String operations.
 */
library LibStrings {

    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` 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);
        uint256 index = digits - 1;
        temp = value;
        while (temp != 0) {
            buffer[index--] = bytes1(uint8(48 + temp % 10));
            temp /= 10;
        }
        return string(buffer);
    }

     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] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` representation.
     */
    function toString(int256 value) internal pure returns(string memory){
        if(value > 0){
            return toString(uint256(value));
        } else {
            return string(abi.encodePacked("-", toString(uint256(-value))));
        }
    }
}

File 23 of 23 : LibTokenSilo.sol
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol";
import "../LibAppStorage.sol";
import "../../C.sol";
import "contracts/libraries/LibSafeMath32.sol";
import "contracts/libraries/LibSafeMath128.sol";
import "contracts/libraries/LibSafeMathSigned128.sol";
import "contracts/libraries/LibSafeMathSigned96.sol";
import "contracts/libraries/LibBytes.sol";


/**
 * @title LibTokenSilo
 * @author Publius, Pizzaman1337
 * @notice Contains functions for depositing, withdrawing and claiming
 * whitelisted Silo tokens.
 *
 * For functionality related to Stalk, and Roots, see {LibSilo}.
 */
library LibTokenSilo {
    using SafeMath for uint256;
    using LibSafeMath128 for uint128;
    using LibSafeMath32 for uint32;
    using LibSafeMathSigned128 for int128;
    using SafeCast for int128;
    using SafeCast for uint256;
    using LibSafeMathSigned96 for int96;


    //////////////////////// ENUM ////////////////////////
    /**
     * @dev when a user deposits or withdraws a deposit, the
     * {TrasferSingle} event is emitted. However, in the case
     * of a transfer, this emission is ommited. This enum is
     * used to determine if the event should be emitted.
     */
    enum Transfer {
        emitTransferSingle,
        noEmitTransferSingle
    }

    //////////////////////// EVENTS ////////////////////////

    /**
     * @dev IMPORTANT: copy of {TokenSilo-AddDeposit}, check there for details.
     */
    event AddDeposit(
        address indexed account,
        address indexed token,
        int96 stem,
        uint256 amount,
        uint256 bdv
    );

    // added as the ERC1155 deposit upgrade
    event TransferSingle(
        address indexed operator, 
        address indexed sender, 
        address indexed recipient, 
        uint256 depositId, 
        uint256 amount
    );


    //////////////////////// ACCOUNTING: TOTALS ////////////////////////
    
    /**
     * @dev Increment the total amount and bdv of `token` deposited in the Silo.
     */
    function incrementTotalDeposited(address token, uint256 amount, uint256 bdv) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.siloBalances[token].deposited = s.siloBalances[token].deposited.add(
            amount.toUint128()
        );
        s.siloBalances[token].depositedBdv = s.siloBalances[token].depositedBdv.add(
            bdv.toUint128()
        );
    }

    /**
     * @dev Decrement the total amount and bdv of `token` deposited in the Silo.
     */
    function decrementTotalDeposited(address token, uint256 amount, uint256 bdv) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.siloBalances[token].deposited = s.siloBalances[token].deposited.sub(
            amount.toUint128()
        );
        s.siloBalances[token].depositedBdv = s.siloBalances[token].depositedBdv.sub(
            bdv.toUint128()
        );
    }

    /**
     * @dev Increment the total bdv of `token` deposited in the Silo. Used in Enroot.
     */
    function incrementTotalDepositedBdv(address token, uint256 bdv) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.siloBalances[token].depositedBdv = s.siloBalances[token].depositedBdv.add(
            bdv.toUint128()
        );
    }

    //////////////////////// ADD DEPOSIT ////////////////////////

    /**
     * @return stalk The amount of Stalk received for this Deposit.
     * 
     * @dev Calculate the current BDV for `amount` of `token`, then perform 
     * Deposit accounting.
     */
    function deposit(
        address account,
        address token,
        int96 stem,
        uint256 amount
    ) internal returns (uint256) {
        uint256 bdv = beanDenominatedValue(token, amount);
        return depositWithBDV(account, token, stem, amount, bdv);
    }

    /**
     * @dev Once the BDV received for Depositing `amount` of `token` is known, 
     * add a Deposit for `account` and update the total amount Deposited.
     *
     * `s.ss[token].stalkIssuedPerBdv` stores the number of Stalk per BDV for `token`.
     */
    function depositWithBDV(
        address account,
        address token,
        int96 stem,
        uint256 amount,
        uint256 bdv
    ) internal returns (uint256 stalk) {
        require(bdv > 0, "Silo: No Beans under Token.");
        AppStorage storage s = LibAppStorage.diamondStorage();
        
        incrementTotalDeposited(token, amount, bdv);
        addDepositToAccount(
            account, 
            token, 
            stem, 
            amount, 
            bdv, 
            Transfer.emitTransferSingle  
        ); 
        stalk = bdv.mul(s.ss[token].stalkIssuedPerBdv);
    }

    /**
     * @dev Add `amount` of `token` to a user's Deposit in `stemTipForToken`. Requires a
     * precalculated `bdv`.
     *
     * If a Deposit doesn't yet exist, one is created. Otherwise, the existing
     * Deposit is updated.
     * 
     * `amount` & `bdv` are downcasted uint256 -> uint128 to optimize storage cost,
     * since both values can be packed into one slot.
     * 
     * Unlike {removeDepositFromAccount}, this function DOES EMIT an 
     * {AddDeposit} event. See {removeDepositFromAccount} for more details.
     */
    function addDepositToAccount(
        address account,
        address token,
        int96 stem,
        uint256 amount,
        uint256 bdv,
        Transfer transferType
    ) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 depositId = LibBytes.packAddressAndStem(
            token,
            stem
        );

        // add amount to the deposits, and update the deposit.
        s.a[account].deposits[depositId].amount = 
            s.a[account].deposits[depositId].amount.add(amount.toUint128());
        s.a[account].deposits[depositId].bdv = 
            s.a[account].deposits[depositId].bdv.add(bdv.toUint128());
        
        // update the mow status (note: mow status is per token, not per depositId)
        // SafeMath not necessary as the bdv is already checked to be <= type(uint128).max
        s.a[account].mowStatuses[token].bdv = uint128(s.a[account].mowStatuses[token].bdv.add(uint128(bdv)));

        /** 
         *  {addDepositToAccount} is used for both depositing and transferring deposits.
         *  In the case of a deposit, only the {TransferSingle} Event needs to be emitted.
         *  In the case of a transfer, a different {TransferSingle}/{TransferBatch} 
         *  Event is emitted in {TokenSilo._transferDeposit(s)}, 
         *  and thus, this event is ommited.
         */
        if(transferType == Transfer.emitTransferSingle){
            emit TransferSingle(
                msg.sender, // operator
                address(0), // from
                account, // to
                uint256(depositId), // depositID
                amount // token amount
            );
        }
        emit AddDeposit(account, token, stem, amount, bdv);
    }

    //////////////////////// REMOVE DEPOSIT ////////////////////////

    /**
     * @dev Remove `amount` of `token` from a user's Deposit in `stem`.
     *
     * A "Crate" refers to the existing Deposit in storage at:
     *  `s.a[account].deposits[token][stem]`
     *
     * Partially removing a Deposit should scale its BDV proportionally. For ex.
     * removing 80% of the tokens from a Deposit should reduce its BDV by 80%.
     *
     * During an update, `amount` & `bdv` are cast uint256 -> uint128 to
     * optimize storage cost, since both values can be packed into one slot.
     *
     * This function DOES **NOT** EMIT a {RemoveDeposit} event. This
     * asymmetry occurs because {removeDepositFromAccount} is called in a loop
     * in places where multiple deposits are removed simultaneously, including
     * {TokenSilo-removeDepositsFromAccount} and {TokenSilo-_transferDeposits}.
     */

    function removeDepositFromAccount(
        address account,
        address token,
        int96 stem,
        uint256 amount
    ) internal returns (uint256 crateBDV) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 depositId = LibBytes.packAddressAndStem(token,stem);

        uint256 crateAmount = s.a[account].deposits[depositId].amount;
        crateBDV = s.a[account].deposits[depositId].bdv;

        require(amount <= crateAmount, "Silo: Crate balance too low.");

        // Partial remove
        if (amount < crateAmount) {
            uint256 removedBDV = amount.mul(crateBDV).div(crateAmount);
            uint256 updatedBDV = crateBDV.sub(removedBDV);
            uint256 updatedAmount = crateAmount.sub(amount);

            // SafeCast unnecessary b/c updatedAmount <= crateAmount and updatedBDV <= crateBDV, which are both <= type(uint128).max
            s.a[account].deposits[depositId].amount = uint128(updatedAmount);
            s.a[account].deposits[depositId].bdv = uint128(updatedBDV);
            //remove from the mow status bdv amount, which keeps track of total token deposited per farmer
            s.a[account].mowStatuses[token].bdv = s.a[account].mowStatuses[token].bdv.sub(
                removedBDV.toUint128()
            );
            return removedBDV;
        }
        // Full remove
        if (crateAmount > 0) delete s.a[account].deposits[depositId];


        // SafeMath unnecessary b/c crateBDV <= type(uint128).max
        s.a[account].mowStatuses[token].bdv = s.a[account].mowStatuses[token].bdv.sub(
            uint128(crateBDV)
        );
    }

    //////////////////////// GETTERS ////////////////////////

    /**
     * @dev Calculate the BDV ("Bean Denominated Value") for `amount` of `token`.
     * 
     * Makes a call to a BDV function defined in the SiloSettings for this 
     * `token`. See {AppStorage.sol:Storage-SiloSettings} for more information.
     */
    function beanDenominatedValue(address token, uint256 amount)
        internal
        view
        returns (uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        require(s.ss[token].selector != bytes4(0), "Silo: Token not whitelisted");

        (bool success, bytes memory data) = address(this).staticcall(
            encodeBdvFunction(
                token,
                s.ss[token].encodeType,
                s.ss[token].selector,
                amount
            )
        );

        if (!success) {
            if (data.length == 0) revert();
            assembly {
                revert(add(32, data), mload(data))
            }
        }

        assembly {
            bdv := mload(add(data, add(0x20, 0)))
        }
    }

    function encodeBdvFunction(
        address token,
        bytes1 encodeType,
        bytes4 selector,
        uint256 amount
    )
        internal
        pure
        returns (bytes memory callData)
    {
        if (encodeType == 0x00) {
            callData = abi.encodeWithSelector(
                selector,
                amount
            );
        } else if (encodeType == 0x01) {
            callData = abi.encodeWithSelector(
                selector,
                token,
                amount
            );
        } else {
            revert("Silo: Invalid encodeType");
        }
    }

    /**
     * @dev Locate the `amount` and `bdv` for a user's Deposit in storage.
     * 
     * Silo V3 Deposits are stored within each {Account} as a mapping of:
     *  `uint256 DepositID => { uint128 amount, uint128 bdv }`
     *  The DepositID is the concatination of the token address and the stem.
     * 
     * Silo V2 deposits are only usable after a successful migration, see
     * mowAndMigrate within the Migration facet.
     *
     */
    function getDeposit(
        address account,
        address token,
        int96 stem
    ) internal view returns (uint256 amount, uint256 bdv) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 depositId = LibBytes.packAddressAndStem(
            token,
            stem
        );
        amount = s.a[account].deposits[depositId].amount;
        bdv = s.a[account].deposits[depositId].bdv;
    }
    
    /**
     * @dev Get the number of Stalk per BDV per Season for a whitelisted token. Formerly just seeds.
     * Note this is stored as 1e6, i.e. 1_000_000 units of this is equal to 1 old seed.
     */
    function stalkEarnedPerSeason(address token) internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return uint256(s.ss[token].stalkEarnedPerSeason);
    }

    /**
     * @dev Get the number of Stalk per BDV for a whitelisted token. Formerly just stalk.
     */
    function stalkIssuedPerBdv(address token) internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return uint256(s.ss[token].stalkIssuedPerBdv);
    }

    /**
     * @dev returns the cumulative stalk per BDV (stemTip) for a whitelisted token.
     */
    function stemTipForToken(address token)
        internal
        view
        returns (int96 _stemTipForToken)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        
        // SafeCast unnecessary because all casted variables are types smaller that int96.
        _stemTipForToken = s.ss[token].milestoneStem +
        int96(s.ss[token].stalkEarnedPerSeason).mul(
            int96(s.season.current).sub(int96(s.ss[token].milestoneSeason))
        ).div(1e6); //round here 
    }

    /**
     * @dev returns the amount of grown stalk a deposit has earned.
     */
    function grownStalkForDeposit(
        address account,
        address token,
        int96 stem
    )
        internal
        view
        returns (uint grownStalk)
    {
        // stemTipForToken(token) > depositGrownStalkPerBdv for all valid Deposits
        int96 _stemTip = stemTipForToken(token);
        require(stem <= _stemTip, "Silo: Invalid Deposit");
         // The check in the above line guarantees that subtraction result is positive
         // and thus the cast to `uint256` is safe.
        uint deltaStemTip = uint256(_stemTip.sub(stem));
        (, uint bdv) = getDeposit(account, token, stem);

        grownStalk = deltaStemTip.mul(bdv);
    }

    /**
     * @dev returns the amount of grown stalk a deposit would have, based on the stem of the deposit.
     */
    function calculateStalkFromStemAndBdv(address token, int96 grownStalkIndexOfDeposit, uint256 bdv)
        internal
        view
        returns (int96 grownStalk)
    {
        // current latest grown stalk index
        int96 _stemTipForToken = stemTipForToken(address(token));

        return _stemTipForToken.sub(grownStalkIndexOfDeposit).mul(toInt96(bdv));
    }

    /**
     * @dev returns the stem of a deposit, based on the amount of grown stalk it has earned.
     */
    function calculateGrownStalkAndStem(address token, uint256 grownStalk, uint256 bdv)
        internal
        view 
        returns (uint256 _grownStalk, int96 stem)
    {
        int96 _stemTipForToken = stemTipForToken(token);
        stem = _stemTipForToken.sub(toInt96(grownStalk.div(bdv)));
        _grownStalk = uint256(_stemTipForToken.sub(stem).mul(toInt96(bdv)));
    }


    /**
     * @dev returns the amount of grown stalk a deposit would have, based on the stem of the deposit.
     * Similar to calculateStalkFromStemAndBdv, but has an additional check to prevent division by 0.
     */
    function grownStalkAndBdvToStem(address token, uint256 grownStalk, uint256 bdv)
        internal
        view
        returns (int96 cumulativeGrownStalk)
    {
        // first get current latest grown stalk index
        int96 _stemTipForToken = stemTipForToken(token);
        // then calculate how much stalk each individual bdv has grown
        // there's a > 0 check here, because if you have a small amount of unripe bean deposit, the bdv could
        // end up rounding to zero, then you get a divide by zero error and can't migrate without losing that deposit

        // prevent divide by zero error
        int96 grownStalkPerBdv = bdv > 0 ? toInt96(grownStalk.div(bdv)) : 0;

        // subtract from the current latest index, so we get the index the deposit should have happened at
        return _stemTipForToken.sub(grownStalkPerBdv);
    }

    function toInt96(uint256 value) internal pure returns (int96) {
        require(value <= uint256(type(int96).max), "SafeCast: value doesn't fit in an int96");
        return int96(value);
    }
}

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

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"_uri","type":"string"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"int96","name":"stem","type":"int96"},{"internalType":"int96","name":"stemTip","type":"int96"}],"name":"imageURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50615eb3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806306fdde03146100515780630e89341c1461006f57806395d89b4114610082578063c20b80711461008a575b600080fd5b61005961009d565b604051610066919061480e565b60405180910390f35b61005961007d366004614196565b6100d4565b610059610226565b610059610098366004614147565b61025d565b60408051808201909152601781527f4265616e7374616c6b2053696c6f204465706f73697473000000000000000000602082015290565b60606000806100e284610309565b9150915060006100f183610315565b90506001600160a01b0383166101225760405162461bcd60e51b815260040161011990614841565b60405180910390fd5b600061012d846103f6565b610141856001600160a01b031660146105c6565b61014c8860206105c6565b61015886600b0b610757565b61016961016489610813565b610854565b610177888803600b0b610854565b6101836101648b61092f565b60405160200161019997969594939291906143a1565b60405160208183030381529060405290506101fb816101b986868661025d565b6040516020016101c9919061451f565b60408051601f19818403018152908290526101e7929160200161458b565b60405160208183030381529060405261096c565b60405160200161020b91906147c9565b6040516020818303038152906040529450505050505b919050565b60408051808201909152600781527f4445504f53495400000000000000000000000000000000000000000000000000602082015290565b606061027261026d858585610aad565b61096c565b60405160200180807f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815250601a0182805190602001908083835b602083106102cc5780518252601f1990920191602091820191016102ad565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405290509392505050565b606081901c815b915091565b600080610320610c51565b6001600160a01b038416600090815260398201602052604090205460038201549192506103b991620f4240916103b09161037a9163ffffffff918216600b0b916c01000000000000000000000000909104811690610c5616565b6001600160a01b038716600090815260398601602052604090205463ffffffff6401000000009091048116600b0b9190610cce16565b600b0b90610d9e565b6001600160a01b039093166000908152603990910160205260409020547001000000000000000000000000000000009004600b0b91909101919050565b60606001600160a01b03821673bea0000029ad1c77d3d5d23ba2d8893db9d1efab141561043e57506040805180820190915260048152632122a0a760e11b6020820152610221565b6001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49141561049d575060408051808201909152600881527f4245414e334352560000000000000000000000000000000000000000000000006020820152610221565b6001600160a01b038216731bea0050e63e05fbb5d8ba2f10cf5800b622444914156104e557506040805180820190915260068152653ab92122a0a760d11b6020820152610221565b6001600160a01b038216731bea3ccd22f4ebd3d37d731ba31eeca95713716d141561053057506040805180820190915260098152680eae4848a829c8aa8960bb1b6020820152610221565b6001600160a01b03821673bea0e11282e2bb5893bece110cf199501e872bad141561057957506040805180820190915260078152660848a829c8aa8960cb1b6020820152610221565b6040805162461bcd60e51b815260206004820152601660248201527f746f6b656e206e6f742077686974656c69737465642e00000000000000000000604482015290519081900360640190fd5b606060008260020260020167ffffffffffffffff811180156105e757600080fd5b506040519080825280601f01601f191660200182016040528015610612576020820181803683370190505b509050600360fc1b8160008151811061062757fe5b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061066c57fe5b60200101906001600160f81b031916908160001a905350600160028402015b60018111156106fa577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106106c357fe5b1a60f81b8282815181106106d357fe5b60200101906001600160f81b031916908160001a90535060049490941c936000190161068b565b50831561074e576040805162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015290519081900360640190fd5b90505b92915050565b606060008213156107725761076b82610854565b9050610221565b61077e82600003610854565b60405160200180807f2d0000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b602083106107d85780518252601f1990920191602091820191016107b9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040529050610221565b60008061081e610c51565b6001600160a01b039390931660009081526039939093016020525050604090205468010000000000000000900463ffffffff1690565b60608161087957506040805180820190915260018152600360fc1b6020820152610221565b8160005b811561089157600101600a8204915061087d565b60008167ffffffffffffffff811180156108aa57600080fd5b506040519080825280601f01601f1916602001820160405280156108d5576020820181803683370190505b50859350905060001982015b831561092657600a840660300160f81b8282806001900393508151811061090457fe5b60200101906001600160f81b031916908160001a905350600a840493506108e1565b50949350505050565b60008061093a610c51565b6001600160a01b0393909316600090815260399390930160205250506040902054640100000000900463ffffffff1690565b606081516000141561098d5750604080516020810190915260008152610221565b60006040518060600160405280604081526020016154e8604091399050600060038451600201816109ba57fe5b0460040267ffffffffffffffff811180156109d457600080fd5b506040519080825280601f01601f1916602001820160405280156109ff576020820181803683370190505b509050600182016020820185865187015b80821015610a6b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250610a10565b5050600386510660018114610a875760028114610a9a57610aa2565b603d6001830353603d6002830353610aa2565b603d60018303535b509195945050505050565b6060828203610abb81610e73565b610ac361132c565b610acc836113a2565b610ad68888611431565b604051602001806092615d89823960920185805190602001908083835b60208310610b125780518252601f199092019160209182019101610af3565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b60208310610b5a5780518252601f199092019160209182019101610b3b565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b60208310610ba25780518252601f199092019160209182019101610b83565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310610bea5780518252601f199092019160209182019101610bcb565b5181516020939093036101000a60001901801990911692169190911790527f3c2f7376673e000000000000000000000000000000000000000000000000000092019182525060408051808303601919018152600690920190529a9950505050505050505050565b600090565b6000818303600b83900b8213801590610c75575083600b0b81600b0b13155b80610c935750600083600b0b128015610c93575083600b0b81600b0b135b61074e5760405162461bcd60e51b8152600401808060200182810382526024815260200180615c166024913960400191505060405180910390fd5b600082600b0b60001415610ce457506000610751565b82600b0b600019148015610d085750600b82900b6b7fffffffffffffffffffffff19145b15610d445760405162461bcd60e51b815260040180806020018281038252602781526020018061585a6027913960400191505060405180910390fd5b6000828402905082600b0b84600b0b82600b0b81610d5e57fe5b05600b0b1461074e5760405162461bcd60e51b815260040180806020018281038252602781526020018061585a6027913960400191505060405180910390fd5b600081600b0b60001415610df9576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600b0b600019148015610e1d5750600b83900b6b7fffffffffffffffffffffff19145b15610e595760405162461bcd60e51b81526004018080602001828103825260218152602001806153ac6021913960400191505060405180910390fd5b600082600b0b84600b0b81610e6a57fe5b05949350505050565b60606000610e80836115fc565b5090506000610e9082600461164d565b9050610e9a6116b4565b610ea2611727565b610eaa611a4d565b610eb384611b1b565b610ebc88611d49565b610ec461261f565b610ecc612681565b610ed4612728565b610edc612739565b610ee46127ef565b610eec6127fb565b610ef4612807565b610efc612813565b60405160200180807f3c646566733e00000000000000000000000000000000000000000000000000008152506006018e805190602001908083835b60208310610f565780518252601f199092019160209182019101610f37565b6001836020036101000a0380198251168184511680821785525050505050509050018d805190602001908083835b60208310610fa35780518252601f199092019160209182019101610f84565b51815160209384036101000a60001901801990921691161790528f5191909301928f0191508083835b60208310610feb5780518252601f199092019160209182019101610fcc565b51815160209384036101000a60001901801990921691161790528e5191909301928e0191508083835b602083106110335780518252601f199092019160209182019101611014565b51815160209384036101000a60001901801990921691161790528d5191909301928d0191508083835b6020831061107b5780518252601f19909201916020918201910161105c565b51815160209384036101000a60001901801990921691161790528c5191909301928c0191508083835b602083106110c35780518252601f1990920191602091820191016110a4565b51815160209384036101000a60001901801990921691161790528b5191909301928b0191508083835b6020831061110b5780518252601f1990920191602091820191016110ec565b51815160209384036101000a60001901801990921691161790528a5191909301928a0191508083835b602083106111535780518252601f199092019160209182019101611134565b51815160209384036101000a600019018019909216911617905289519190930192890191508083835b6020831061119b5780518252601f19909201916020918201910161117c565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b602083106111e35780518252601f1990920191602091820191016111c4565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b6020831061122b5780518252601f19909201916020918201910161120c565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106112735780518252601f199092019160209182019101611254565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106112bb5780518252601f19909201916020918201910161129c565b6001836020036101000a038019825116818451168082178552505050505050905001807f3c2f646566733e000000000000000000000000000000000000000000000000008152506007019d505050505050505050505050505060405160208183030381529060405292505050919050565b606060405160200180806157d2602d91397f2332353333323600000000000000000000000000000000000000000000000000602d8201527f222f3e000000000000000000000000000000000000000000000000000000000060348201526040805160178184030181526037909201905291505090565b60606113ad82612890565b604051602001806054615c3a823960540182805190602001908083835b602083106113e95780518252601f1990920191602091820191016113ca565b5181516020939093036101000a6000190180199091169216919091179052631e17b39f60e11b92019182525060408051808303601b1901815260049092019052949350505050565b606061143c83612fba565b611451611448856103f6565b60f06004613062565b61145a856131dd565b61146385613320565b604051602001806041615881823960410185805190602001908083835b6020831061149f5780518252601f199092019160209182019101611480565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b602083106114e75780518252601f1990920191602091820191016114c8565b6001836020036101000a0380198251168184511680821785525050505050509050018061597a6043913960430183805190602001908083835b6020831061153f5780518252601f199092019160209182019101611520565b6001836020036101000a03801982511681845116808217855250505050505090500180615d296060913960600182805190602001908083835b602083106115975780518252601f199092019160209182019101611578565b5181516020939093036101000a60001901801990911692169190911790527f3c2f746578743e00000000000000000000000000000000000000000000000000920191825250604080518083036018190181526007909201905298975050505050505050565b60008061160e600b84900b60c861337f565b9150611626600161162084601061337f565b906133e6565b9050600061163583601061164d565b1115610310576116468160016133e6565b9050915091565b60008082116116a3576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b8183816116ac57fe5b069392505050565b6040517f3c672069643d22706c6f74223e0000000000000000000000000000000000000060208201908152606091602d01606c614ae68239606c0180615427606c9139606c0160686151328239631e17b39f60e11b606882015260408051604c818403018152606c909201905291505090565b6060611753604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b6117a0604051806040016040528060078152602001666c656166526f7760c81b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6117ed604051806040016040528060078152602001666c656166526f7760c81b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b61183a604051806040016040528060078152602001666c656166526f7760c81b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b611887604051806040016040528060078152602001666c656166526f7760c81b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b60405160200180807f3c672069643d2266756c6c4c656166506c6f74223e000000000000000000000081525060150186805190602001908083835b602083106118e15780518252601f1990920191602091820191016118c2565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b602083106119295780518252601f19909201916020918201910161190a565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b602083106119715780518252601f199092019160209182019101611952565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106119b95780518252601f19909201916020918201910161199a565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611a015780518252601f1990920191602091820191016119e2565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040195505050505050604051602081830303815290604052905090565b6060611a79604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b60405160200180807f3c672069643d22656d707479506c6f74223e000000000000000000000000000081525060120182805190602001908083835b60208310611ad35780518252601f199092019160209182019101611ab4565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401915050604051602081830303815290604052905090565b606081611b715750604080517f3c672069643d227061727469616c4c656166526f77223e0000000000000000006020820152631e17b39f60e11b60378201528151601b818303018152603b909101909152610221565b8160011415611bda576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b8160021415611c4d576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b8160031415611cca576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280160296154bf823960290180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b6040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280160296154bf823960290180615e556029913960290180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b60606000611d616010611620600b86900b60c861337f565b90506000611d7a6004611d74848261337f565b9061164d565b90506000611d8983600461164d565b905081612035578015611efc57611dc0604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b611e146040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b60208310611e695780518252601f199092019160209182019101611e4a565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611eb15780518252601f199092019160209182019101611e92565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612035565b611f046137aa565b611f51604051806040016040528060078152602001666c656166526f7760c81b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b60208310611fa65780518252601f199092019160209182019101611f87565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611fee5780518252601f199092019160209182019101611fcf565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b8152506004019250505060405160208183030381529060405293505b816001141561222b5780156121885761204c6138b5565b6120a06040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106120f55780518252601f1990920191602091820191016120d6565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061213d5780518252601f19909201916020918201910161211e565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040192505050604051602081830303815290604052935061222b565b6121906138b5565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106121e55780518252601f1990920191602091820191016121c6565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b816002141561242157801561237e5761224261392e565b6122966040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106122eb5780518252601f1990920191602091820191016122cc565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106123335780518252601f199092019160209182019101612314565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612421565b61238661392e565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106123db5780518252601f1990920191602091820191016123bc565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b8160031415612617578015612574576124386137aa565b61248c6040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106124e15780518252601f1990920191602091820191016124c2565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106125295780518252601f19909201916020918201910161250a565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612617565b61257c6137aa565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106125d15780518252601f1990920191602091820191016125b2565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b505050919050565b6040517f3c672069643d226c656166223e0000000000000000000000000000000000000060208201908152606091602d01610339614b528239631e17b39f60e11b6103398201526040805161031d81840301815261033d909201905291505090565b6040517f3c672069643d2273696c6f223e0000000000000000000000000000000000000060208201908152606091602d0160be61519a823960be016101b9614f7982396101b90160ae614943823960ae01609b615c8e8239609b0160da6155d4823960da0161010a615b0c823961010a0160a4614e8b823960a401605161552882396051016101246156ae8239610124019050604051602081830303815290604052905090565b60606127346000613985565b905090565b6040517f3c672069643d224245414e33435256000000000000000000000000000000000060208201908152606091602f01603a615e1b8239603a01604a614f2f8239604a0160c16152eb823960c10160676159138239606701604661527d8239604601607b614a6b82397f3c2f6c696e6561724772616469656e743e3c2f646566733e0000000000000000607b820152631e17b39f60e11b60938201526040805160778184030181526097909201905291505090565b60606127346001613985565b60606127346000613b08565b60606127346001613b08565b6040517f3c672069643d226c656166526f77223e00000000000000000000000000000000602082019081526060916030016025615258823960250160286152c3823960280160296154bf823960290180615e5560299139631e17b39f60e11b602982015260408051600d818403018152602d909201905291505090565b60606000604051806102a001604052806040518060400160405280604419815260200160a319815250815260200160405180604001604052806045815260200160a3198152508152602001604051806040016040528060008152602001607b1981525081526020016040518060400160405280608a8152602001607b19815250815260200160405180604001604052806089198152602001607b198152508152602001604051806040016040528060441981526020016053198152508152602001604051806040016040528060458152602001605319815250815260200160405180604001604052806089198152602001602b198152508152602001604051806040016040528060008152602001602b1981525081526020016040518060400160405280608a8152602001602b198152508152602001604051806040016040528060441981526020016003198152508152602001604051806040016040528060458152602001600319815250815260200160405180604001604052806089198152602001602481525081526020016040518060400160405280608a81526020016024815250815260200160405180604001604052806044198152602001604c8152508152602001604051806040016040528060458152602001604c81525081526020016040518060400160405280608919815260200160748152508152602001604051806040016040528060008152602001607481525081526020016040518060400160405280608a815260200160748152508152602001604051806040016040528060458152602001609c815250815260200160405180604001604052806044198152602001609c81525081525090506000604051806102a001604052806014815260200160138152602001600d81526020016012815260200160158152602001600e8152602001600c8152602001600f815260200160058152602001600b81526020016006815260200160048152602001600781526020016003815260200160088152602001600281526020016010815260200160018152602001600a8152602001600981526020016011815250905060606000612baf866115fc565b91505060005b6015811015612faf576000848260158110612bcc57fe5b6020020151905082811015612ce95783612c336040518060400160405280600c81526020016b199d5b1b13195859941b1bdd60a21b815250888560158110612c1057fe5b602002015151898660158110612c2257fe5b602002015160016020020151613062565b6040516020018083805190602001908083835b60208310612c655780518252601f199092019160209182019101612c46565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612cad5780518252601f199092019160209182019101612c8e565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529350612f28565b82811415612e30578260011415612de55783612d2f6040518060400160405280600c81526020016b199d5b1b13195859941b1bdd60a21b815250888560158110612c1057fe5b6040516020018083805190602001908083835b60208310612d615780518252601f199092019160209182019101612d42565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612da95780518252601f199092019160209182019101612d8a565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529350612e2b565b83612c336040518060400160405280600f81526020017f7061727469616c4c656166506c6f740000000000000000000000000000000000815250888560158110612c1057fe5b612f28565b83612e766040518060400160405280600981526020017f656d707479506c6f740000000000000000000000000000000000000000000000815250888560158110612c1057fe5b6040516020018083805190602001908083835b60208310612ea85780518252601f199092019160209182019101612e89565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612ef05780518252601f199092019160209182019101612ed1565b6001836020036101000a0380198251168184511680821785525050505050509050019250505060405160208183030381529060405293505b81600b1415612fa657836040516020018082805190602001908083835b60208310612f645780518252601f199092019160209182019101612f45565b6001836020036101000a03801982511681845116808217855250505050505090500180614905603e9139603e0191505060405160208183030381529060405293505b50600101612bb5565b509095945050505050565b6060612fc5826103f6565b60405160200180605b6157ff8239605b0182805190602001908083835b602083106130015780518252601f199092019160209182019101612fe2565b5181516020939093036101000a60001901801990911692169190911790527f204465706f7369743c2f746578743e000000000000000000000000000000000092019182525060408051808303601019018152600f9092019052949350505050565b60608361306e84613c9f565b61307784613c9f565b6040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120184805190602001908083835b602083106130c65780518252601f1990920191602091820191016130a7565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528551600590910192860191508083835b6020831061311f5780518252601f199092019160209182019101613100565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528451600590910192850191508083835b602083106131785780518252601f199092019160209182019101613159565b5181516020939093036101000a60001901801990911692169190911790527f22202f3e0000000000000000000000000000000000000000000000000000000092019182525060408051808303601b190181526004909201905298975050505050505050565b60606131e882613cbf565b6131f183613cbf565b60405160200180605c6148a98239605c01605a6153cd8239605a0183805190602001908083835b602083106132375780518252601f199092019160209182019101613218565b5181516020939093036101000a60001901801990911692169190911790527f3c2f747370616e3e3c2f746578743e0000000000000000000000000000000000920191825250600f01605c6148a98239605c01605b6155798239605b0182805190602001908083835b602083106132be5780518252601f19909201916020918201910161329f565b5181516020939093036101000a60001901801990911692169190911790527f3c2f747370616e3e3c2f746578743e000000000000000000000000000000000092019182525060408051808303601019018152600f909201905295945050505050565b6060600082600b0b1261335357620186a082600b0b13156133475761076b82600b0b613cd5565b61076b82600b0b610854565b620186a082600003600b0b13156133735761077e82600003600b0b613cd5565b61076b82600b0b610757565b60008082116133d5576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816133de57fe5b049392505050565b60008282018381101561074e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60608361344c84613c9f565b61345584613c9f565b6040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120184805190602001908083835b602083106134a45780518252601f199092019160209182019101613485565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528551600590910192860191508083835b602083106134fd5780518252601f1990920191602091820191016134de565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528451600590910192850191508083835b602083106135565780518252601f199092019160209182019101613537565b5181516020939093036101000a60001901801990911692169190911790527f22207472616e73666f726d3d227363616c6528312e3429222f3e00000000000092019182525060408051808303600519018152601a909201905298975050505050505050565b6060846135c785613c9f565b6135d085613c9f565b846040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120185805190602001908083835b602083106136205780518252601f199092019160209182019101613601565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528651600590910192870191508083835b602083106136795780518252601f19909201916020918201910161365a565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528551600590910192860191508083835b602083106136d25780518252601f1990920191602091820191016136b3565b51815160209384036101000a60001901801990921691161790527f222066696c6c3d22000000000000000000000000000000000000000000000000919093019081528451600890910192850191508083835b602083106137435780518252601f199092019160209182019101613724565b5181516020939093036101000a60001901801990911692169190911790527f22207472616e73666f726d3d227363616c6528312e3429222f3e00000000000092019182525060408051808303600519018152601a90920190529a9950505050505050505050565b60606137b461392e565b613801604051806040016040528060078152602001666c656166526f7760c81b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018083805190602001908083835b602083106138335780518252601f199092019160209182019101613814565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061387b5780518252601f19909201916020918201910161385c565b6001836020036101000a03801982511681845116808217855250505050505090500192505050604051602081830303815290604052905090565b60606138e1604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b613801604051806040016040528060078152602001666c656166526f7760c81b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b60606139386138b5565b613801604051806040016040528060078152602001666c656166526f7760c81b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6060816139ae57604051806040016040528060048152602001632122a0a760e11b8152506139ce565b604051806040016040528060068152602001653ab92122a0a760d11b8152505b826139f857604051806040016040528060078152602001662334364239353560c81b815250613a19565b604051806040016040528060078152602001662337463535333360c81b8152505b6040516020018080661e339034b21e9160c91b81525060070183805190602001908083835b60208310613a5d5780518252601f199092019160209182019101613a3e565b6001836020036101000a03801982511681845116808217855250505050505090500180615493602c9139602c0182805190602001908083835b60208310613ab55780518252601f199092019160209182019101613a96565b6001836020036101000a038019825116818451168082178552505050505050905001806149f1607a9139631e17b39f60e11b607a82015260408051808303605e018152607e909201905295945050505050565b606081613b3457604051806040016040528060078152602001660848a829c8aa8960cb1b815250613b57565b604051806040016040528060098152602001680eae4848a829c8aa8960bb1b8152505b82613b8157604051806040016040528060078152602001662334364239353560c81b815250613ba2565b604051806040016040528060078152602001662337463535333360c81b8152505b6040516020018080661e339034b21e9160c91b81525060070183805190602001908083835b60208310613be65780518252601f199092019160209182019101613bc7565b6001836020036101000a03801982511681845116808217855250505050505090500180615493602c9139602c0182805190602001908083835b60208310613c3e5780518252601f199092019160209182019101613c1f565b6001836020036101000a038019825116818451168082178552505050505050905001806158c26051913960510161014f6159bd8239631e17b39f60e11b61014f82015260408051808303610133018152610153909201905295945050505050565b60606000821215613cb65761077e82600003610854565b61076b82610854565b60606107516001600160a01b03831660146105c6565b6060620f4240821015613ced5761076b826005613f40565b62989680821015613d035761076b826006613f40565b6305f5e100821015613d1a5761076b826007613f40565b633b9aca00821015613d315761076b826008613f40565b6402540be400821015613d495761076b826009613f40565b64174876e800821015613d615761076b82600a613f40565b64e8d4a51000821015613d795761076b82600b613f40565b6509184e72a000821015613d925761076b82600c613f40565b655af3107a4000821015613dab5761076b82600d613f40565b66038d7ea4c68000821015613dc55761076b82600e613f40565b662386f26fc10000821015613ddf5761076b82600f613f40565b67016345785d8a0000821015613dfa5761076b826010613f40565b670de0b6b3a7640000821015613e155761076b826011613f40565b678ac7230489e80000821015613e305761076b826012613f40565b68056bc75e2d63100000821015613e4c5761076b826013613f40565b683635c9adc5dea00000821015613e685761076b826014613f40565b69021e19e0c9bab2400000821015613e855761076b826015613f40565b69152d02c7e14af6800000821015613ea25761076b826016613f40565b69d3c21bcecceda1000000821015613ebf5761076b826017613f40565b6a084595161401484a000000821015613edd5761076b826018613f40565b6a52b7d2dcc80cd2e4000000821015613efb5761076b826019613f40565b6b033b2e3c9fd0803ce8000000821015613f1a5761076b82601a613f40565b6b204fce5e3e25026110000000821015613f395761076b82601b613f40565b61076b82601c5b6060613f5361016484600a85900a61337f565b613f75610164620186a0611d74613f6b8760056140d8565b8890600a0a61337f565b613f7e84610854565b6040516020018084805190602001908083835b60208310613fb05780518252601f199092019160209182019101613f91565b6001836020036101000a038019825116818451168082178552505050505050905001807f2e0000000000000000000000000000000000000000000000000000000000000081525060010183805190602001908083835b602083106140255780518252601f199092019160209182019101614006565b6001836020036101000a038019825116818451168082178552505050505050905001807f650000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b6020831061409a5780518252601f19909201916020918201910161407b565b6001836020036101000a0380198251168184511680821785525050505050509050019350505050604051602081830303815290604052905092915050565b60008282111561412f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b8035600b81900b811461022157600080fd5b60008060006060848603121561415b578283fd5b83356001600160a01b0381168114614171578384fd5b925061417f60208501614135565b915061418d60408501614135565b90509250925092565b6000602082840312156141a7578081fd5b5035919050565b600081516141c0818560208601614878565b9290920192915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d2c207b202274726169745f74797065223a202267726f776e207374616c6b2081527f70657220424456222c2022646973706c61795f74797065223a20226e756d626560208201527f72222c202276616c7565223a20000000000000000000000000000000000000006040820152604d0190565b7f227d2c207b202274726169745f74797065223a20227374656d222c202264697381527f706c61795f74797065223a20226e756d626572222c202276616c7565223a20006020820152603f0190565b7f7d2c207b202274726169745f74797065223a2022696e6974616c207374616c6b81527f2070657220424456222c2022646973706c61795f74797065223a20226e756d6260208201527f6572222c202276616c7565223a200000000000000000000000000000000000006040820152604e0190565b7f7d2c207b202274726169745f74797065223a20227374616c6b2067726f776e2081527f706572204244562070657220736561736f6e222c2022646973706c61795f747960208201527f7065223a20226e756d626572222c202276616c7565223a200000000000000000604082015260580190565b60007f2c202261747472696275746573223a205b207b202274726169745f747970652282527f3a2022546f6b656e222c202276616c7565223a20220000000000000000000000602083015288516143ff816035850160208d01614878565b7f227d2c207b202274726169745f74797065223a2022546f6b656e2041646472656035918401918201527f7373222c202276616c7565223a2022000000000000000000000000000000000060558201528851614462816064840160208d01614878565b7f227d2c207b202274726169745f74797065223a20224964222c202276616c7565606492909101918201527f223a202200000000000000000000000000000000000000000000000000000000608482015287516144c6816088840160208c01614878565b61451061450a6145056144ff6144fa6144f46144ef6144e96088898b0101614268565b8f6141ae565b6142b7565b8c6141ae565b6141f3565b896141ae565b61432c565b866141ae565b9b9a5050505050505050505050565b60007f2c2022696d616765223a202200000000000000000000000000000000000000008252825161455781600c850160208701614878565b7f2200000000000000000000000000000000000000000000000000000000000000600c939091019283015250600d01919050565b60007f7b0000000000000000000000000000000000000000000000000000000000000082527f226e616d65223a20224265616e7374616c6b2053696c6f204465706f7369747360018301527f222c20226465736372697074696f6e223a2022416e204552433131353520726560218301527f70726573656e74696e6720616e206173736574206465706f736974656420696e60418301527f20746865204265616e7374616c6b2053696c6f2e2053696c6f204465706f736960618301527f7473206761696e207374616c6b20616e64206265616e20736569676e6f72616760818301527f652e20000000000000000000000000000000000000000000000000000000000060a18301527f5c6e5c6e444953434c41494d45523a204475652064696c6967656e636520697360a48301527f20696d7065726174697665207768656e20617373657373696e6720746869732060c48301527f4e46542e204f70656e73656120616e64206f74686572204e4654206d61726b6560e48301527f74706c616365732063616368652074686520737667206f757470757420616e646101048301527f20746875732c206d6179207265717569726520746865207573657220746f20726101248301527f65667265736820746865206d6574616461746120746f2070726f7065726c79206101448301527f73686f772074686520636f72726563742076616c7565732e22000000000000006101648301526147c16147bc6147b661017d8501876141ae565b856141ae565b6141ca565b949350505050565b60007f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008252825161480181601d850160208701614878565b91909101601d0192915050565b600060208252825180602084015261482d816040850160208701614878565b601f01601f19169190910160400192915050565b6020808252601d908201527f53696c6f3a206d6574616461746120646f6573206e6f74206578697374000000604082015260600190565b60005b8381101561489357818101518382015260200161487b565b838111156148a2576000848401525b5050505056fe3c7465787420783d223132372220793d223334332220666f6e742d73697a653d223130222066696c6c3d2257686974652220746578742d616e63686f723d226d6964646c652220666f6e742d66616d696c793d22667574757261223e3c75736520786c696e6b3a687265663d222373696c6f2220783d2234372220793d22353522207472616e73666f726d3d227363616c6528312e3729222f3e3c7061746820643d224d35372e34382031392e3438324335372e36343520392e32342034342e3937382e3732372032392e3138372e3436382031332e3339372e32312e34363320382e3330332e3239382031382e3534362e3133342032382e3738382031322e382033372e332032382e3539312033372e35366331352e37392e3235382032382e3732342d372e3833352032382e3838392d31382e3037385a222066696c6c3d2223434343222f3e222f3e3c7061746820643d226d372e36383720312e3236352d332e35303420392e3336532e32393820332e39393920372e36383720312e3236365a6d2d322e36393120382e373820322e3436322d362e36393173342e35333820332e36372d322e34363220362e3639315a222066696c6c3d2223666666222f3e3c73746f70206f66667365743d222e353136222073746f702d636f6c6f723d2223463046353037222f3e3c73746f70206f66667365743d222e373334222073746f702d636f6c6f723d2223383543443735222f3e3c73746f70206f66667365743d2231222073746f702d636f6c6f723d2223303239444642222f3e3c7061746820643d224d37392e35373238203132392e3236354c3132372e343639203135362e3833334c3137352e343433203132392e3234354c3132372e343639203130312e3639374c37392e35373238203132392e3236355a222066696c6c3d2223393434413237222f3e3c7061746820643d224d3137312e383834203131382e39383361342e39333220342e3933322030203020312d312e30313820322e36303620342e37313520342e3731352030203020312d312e38373820312e343339632d2e3436352e3139352d312e3733352e3732372d322e3336342e3137362d2e32343620332e3239382d312e35393320362e3531322d322e32353320372e39353461342e35333220342e3533322030203020312d2e3331332d2e393333632d2e3231312d2e3937352d2e3033382d312e3736332e3037382d322e3239352e3230322d2e3932312e3335332d312e3631322e3436372d322e31342d312e3137372e3639342d322e3634322e3536392d332e3535382d2e3237322d2e3739362d2e3733322d312e3038332d312e3932312d2e3734332d332e3033342e3439382e30313120312e3933392e31303920332e32343720312e31363761352e313320352e313320302030203120312e323120312e343133632e3135392d2e37342e3139392d2e3935382e3233382d312e3137392e3230392d312e3231332e3332322d312e3837322e3237342d322e37323461372e373320372e37332030203020302d2e3930382d332e313737632d2e3737322e3431352d312e3738392e3139362d322e3337382d2e3330342d2e3333392d2e3238372d2e3535362d2e3638322d2e3736342d312e3639326131322e3733392031322e3733392030203020312d2e3137362d332e393039632e3738392e36303320312e343720312e30313920312e39333720312e3238332e3934342e35333620312e3334342e36333920312e37363120312e3136372e3135322e3139332e3634392e3834322e35383620312e3735312d2e3031312e3137322d2e3035332e3739352d2e34363420312e32393361362e383320362e383320302030203120312e33383420322e323237632e31342e3336382e3234322e3734342e33313120312e31352e3130372d2e3230372e3236312d2e3433392e3531312d2e3732322e3435332d2e3531332e38372d2e39393220312e3630342d312e3238342e3638332d2e32373220312e32382d2e32343920312e3732332d2e32333461352e33303220352e33303220302030203120312e3438362e3237335a222f3e3c70617468206f7061636974793d222e34342220643d224d312e38312032362e353332632e3230362e3439342e34383420312e30352e383620312e36336131302e3236362031302e32363620302030203020322e32373820322e3438364c362e3535322037382e32326131372e3237322031372e3237322030203020312d332d372e3431334c312e38312032362e3533325a222066696c6c3d2223453645364536222f3e222f3e3c7061746820643d226d372e36383720312e3736342d332e35303420392e3336532e32393820342e34393920372e36383720312e3736355a222066696c6c3d2223666666222f3e3c7061746820643d224d2e3436342031392e353434632e3639392031362e35383520312e342033332e31363920322e3039382034392e3735322e30323120322e3338312e343820342e3237382e38383320352e3533392e3237372e38362e37343120322e32373520312e37373820332e3836372e3439342e37353920312e32313220312e3720332e30303220332e33333220312e37333920312e35383620332e333520332e30353620352e37333220342e33393820332e32393320312e38353520362e31353120322e33393620382e37393120322e38393620312e3835352e333520352e3134392e39343820392e3438382e3535366133322e3730372033322e37303720302030203020392e3331352d322e32383763312e3836322d2e37353920342e3634322d312e39313720372e3633332d342e3420312e3334382d312e313220332e3434382d322e38393720352e3139372d352e39356132302e3131342032302e31313420302030203020322e32352d352e393938632e32312d31372e3535322e34322d33352e3130342e3633322d35322e3635376c2d35362e382e393532682e3030315a222066696c6c3d2223423342334233222f3e3c7061746820643d224d3137352e343637203133332e344c3137352e343433203132392e3234354c3132372e343639203135362e3833334c3132372e353037203136302e3930384c3137352e343637203133332e345a222066696c6c3d2223363733333145222f3e3c7061746820643d224d35372e3130382037312e3239632e3138382d31312e3635332d31322e30312d32312e3330332d32372e3234332d32312e3535322d31352e3233342d2e32352d32372e37333620382e3939352d32372e3932332032302e3634392d2e3138372031312e3635342031322e30312032312e3330342032372e3234342032312e3535332031352e3233332e32352032372e3733352d382e3939352032372e3932322d32302e36355a222066696c6c3d2223363636222f3e3c75736520786c696e6b3a687265663d22236c6561662220783d22302220793d2230222f3e3c73746f702073746f702d636f6c6f723d2223383230323032222f3e3c73746f70206f66667365743d222e313832222073746f702d636f6c6f723d2223463731453035222f3e3c75736520786c696e6b3a687265663d22236c6561662220783d222d31322220793d222d37222f3e3c7061746820643d224d382e31333220382e303738632d2e3436362e36342d312e32393720312e3332332d322e36393520312e3939326c322e3132362d352e373737632e3038392e30392e3139332e3230342e332e3333382e3330332e3337352e3632352e3839312e37343420312e3438342e3131372e3538332e303420312e3235332d2e34373520312e3936335a222066696c6c3d2275726c2823612922207374726f6b653d222366666622207374726f6b652d77696474683d222e35222f3e5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f773c747370616e3e3c616e696d617465206174747269627574654e616d653d2278222066726f6d3d223337352220746f3d22353022206475723d223130732220726570656174436f756e743d22696e646566696e69746522202f3e3c7061746820643d224d37392e35333332203133332e3432364c37392e35373237203132392e3236354c3132372e343639203135362e3833334c3132372e353037203136302e3930384c37392e35333332203133332e3432365a222066696c6c3d2223373533393146222f3e223e3c726563742077696474683d22313222206865696768743d223132222072783d2236222066696c6c3d223c75736520786c696e6b3a687265663d22236c6561662220783d222d32342220793d222d3134222f3e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f3c7061746820643d226d33332e3039322034392e3434312d362e3338312031352e323131732d362e3037382d31312e31353920362e3338312d31352e32315a222066696c6c3d2223384538453845222f3e3c747370616e3e3c616e696d617465206174747269627574654e616d653d2278222066726f6d3d2235302220746f3d222d32373522206475723d223130732220726570656174436f756e743d22696e646566696e69746522202f3e3c7061746820643d224d362e3431342032382e38396131352e3737372031352e3737372030203020312d322e3039332d322e313436632d2e3835362d312e3036332d322e3435332d332e3039332d322e3937352d362e3131326131312e3736352031312e3736352030203020312d2e3039332d332e3330376c32352e34332d392e393736632e3034332e3134322e3138382e3535352e3630342e3836382e34362e3334362e3934372e333420312e3038362e3333344c362e3431332032382e383838762e3030325a222066696c6c3d2223453645364536222f3e3c7061746820643d226d32362e3732352036342e3835382d2e3039312d2e313735632d2e3032362d2e3034392d322e3633342d342e3932332d2e3836372d392e333720312e3035372d322e37313720332e3531382d342e37323520372e332d352e3934366c2e3138372d2e3036312d362e35332031352e3535325a6d362e3231322d31352e323638632d332e36323120312e3231372d352e39393120332e3136382d372e30323220352e3739382d312e35333820332e3930382e33353520382e3136362e37383820392e3035346c362e3233342d31342e3835325a4d32382e3039332036332e3733376c342e3438342d31302e383773372e33363520362e3333372d342e3438342031302e38375a222066696c6c3d2223384538453845222f3e3c2f673e3c726563742077696474683d2232353522206865696768743d22333530222072783d223130222066696c6c3d223c7465787420783d2231302220793d2231342e352220666f6e742d73697a653d223132222066696c6c3d2257686974652220746578742d616e63686f723d2273746172742220666f6e742d66616d696c793d22667574757261223e5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f773c7265637420783d22302220793d2230222077696474683d2232353522206865696768743d223230222072783d2235222066696c6c3d2223323432343234222f3e222f3e3c7061746820643d226d372e36383420312e3236352d332e35303520392e3336632e30303320302d332e3838342d362e36323520332e3530352d392e33365a222066696c6c3d2223666666222f3e3c646566733e3c6c696e6561724772616469656e742069643d2261222078313d22362e3935222079313d22332e383533222078323d22362e3935222079323d2231302e35343422206772616469656e74556e6974733d227573657253706163654f6e557365223e3c7265637420783d22302220793d22333330222077696474683d2232353522206865696768743d223230222072783d2235222066696c6c3d2223323432343234222f3e3c7061746820643d224d382e39353220362e393836612e3036332e3036332030203020312d2e3032322e303033632d2e37312e31332d312e3432342e3235352d322e3133342e3338312d2e3238312e3035322d2e3536352e3130332d2e3834362e313532612e3033362e3033362030203020312d2e30323620306c322e31342d352e3632352e3030342d2e303033632e32393720312e3730322e353920332e3339342e38383420352e3039325a6d2d2e3138372e343738632d312e3236362e3835392d322e35333120312e3732312d332e3820322e35386c2e3738312d322e303534632e3030372e3030342e3031332030202e3032332030202e3735392d2e31333220312e3531342d2e32363820322e32372d2e346c2e3639372d2e3132362e30332d2e303036632d2e3030342e3030332030202e3030362030202e3030365a222066696c6c3d2223303030222f3e3c70617468206f7061636974793d222e33332220643d224d312e3437372031362e303239632e32352d2e3933312e3730362d322e32353820312e35372d332e3639352e3635352d312e30393220312e3239322d312e38323520312e37362d322e3335382e3538342d2e36363520312e3737362d312e39333420332e3637392d332e323920322e3935332d322e31303520352e3639362d332e303520372e3732332d332e37336133372e33352033372e333520302030203120362e3438352d312e3534376c352e32343220342e33313661312e343820312e34382030203020302d312e3231342e3936374c312e34382031362e3033682d2e3030325a222066696c6c3d2223393939222f3e5369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f773c75736520786c696e6b3a687265663d222373696c6f2220783d2239392220793d223535222f3e3c672069643d22616c6c506c6f742220636c69702d706174683d2275726c2823626f726465724d61736b29223e3c7061746820643d224d33302e33313420372e313337632e3030392d2e3536312d2e36382d312e3032382d312e3533382d312e3034322d2e3835392d2e3031342d312e3536322e34332d312e3537312e3939312d2e30312e3536322e363820312e30323820312e35333820312e3034322e3835392e30313520312e3536322d2e343320312e35372d2e39395a222066696c6c3d2223363636222f3e3c7465787420783d223233352220793d2231342e352220666f6e742d73697a653d223132222066696c6c3d2257686974652220746578742d616e63686f723d22656e642220666f6e742d66616d696c793d22667574757261223e5374656d3a203c73766720636c6173733d22737667426f6479222077696474683d2232353522206865696768743d22333530222076696577426f783d2230203020323535203335302220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b223e223e3c7265637420793d222e35222077696474683d22313222206865696768743d223132222072783d2236222066696c6c3d22233436423935353c75736520786c696e6b3a687265663d22236c6561662220783d222d33362220793d222d3231222f3ea2646970667358221220dc0a0dfe5561279103de1e337f625a3294dd4c3482bde66c9d10efa5c65a279e64736f6c63430007060033

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806306fdde03146100515780630e89341c1461006f57806395d89b4114610082578063c20b80711461008a575b600080fd5b61005961009d565b604051610066919061480e565b60405180910390f35b61005961007d366004614196565b6100d4565b610059610226565b610059610098366004614147565b61025d565b60408051808201909152601781527f4265616e7374616c6b2053696c6f204465706f73697473000000000000000000602082015290565b60606000806100e284610309565b9150915060006100f183610315565b90506001600160a01b0383166101225760405162461bcd60e51b815260040161011990614841565b60405180910390fd5b600061012d846103f6565b610141856001600160a01b031660146105c6565b61014c8860206105c6565b61015886600b0b610757565b61016961016489610813565b610854565b610177888803600b0b610854565b6101836101648b61092f565b60405160200161019997969594939291906143a1565b60405160208183030381529060405290506101fb816101b986868661025d565b6040516020016101c9919061451f565b60408051601f19818403018152908290526101e7929160200161458b565b60405160208183030381529060405261096c565b60405160200161020b91906147c9565b6040516020818303038152906040529450505050505b919050565b60408051808201909152600781527f4445504f53495400000000000000000000000000000000000000000000000000602082015290565b606061027261026d858585610aad565b61096c565b60405160200180807f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000815250601a0182805190602001908083835b602083106102cc5780518252601f1990920191602091820191016102ad565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405290509392505050565b606081901c815b915091565b600080610320610c51565b6001600160a01b038416600090815260398201602052604090205460038201549192506103b991620f4240916103b09161037a9163ffffffff918216600b0b916c01000000000000000000000000909104811690610c5616565b6001600160a01b038716600090815260398601602052604090205463ffffffff6401000000009091048116600b0b9190610cce16565b600b0b90610d9e565b6001600160a01b039093166000908152603990910160205260409020547001000000000000000000000000000000009004600b0b91909101919050565b60606001600160a01b03821673bea0000029ad1c77d3d5d23ba2d8893db9d1efab141561043e57506040805180820190915260048152632122a0a760e11b6020820152610221565b6001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49141561049d575060408051808201909152600881527f4245414e334352560000000000000000000000000000000000000000000000006020820152610221565b6001600160a01b038216731bea0050e63e05fbb5d8ba2f10cf5800b622444914156104e557506040805180820190915260068152653ab92122a0a760d11b6020820152610221565b6001600160a01b038216731bea3ccd22f4ebd3d37d731ba31eeca95713716d141561053057506040805180820190915260098152680eae4848a829c8aa8960bb1b6020820152610221565b6001600160a01b03821673bea0e11282e2bb5893bece110cf199501e872bad141561057957506040805180820190915260078152660848a829c8aa8960cb1b6020820152610221565b6040805162461bcd60e51b815260206004820152601660248201527f746f6b656e206e6f742077686974656c69737465642e00000000000000000000604482015290519081900360640190fd5b606060008260020260020167ffffffffffffffff811180156105e757600080fd5b506040519080825280601f01601f191660200182016040528015610612576020820181803683370190505b509050600360fc1b8160008151811061062757fe5b60200101906001600160f81b031916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061066c57fe5b60200101906001600160f81b031916908160001a905350600160028402015b60018111156106fa577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106106c357fe5b1a60f81b8282815181106106d357fe5b60200101906001600160f81b031916908160001a90535060049490941c936000190161068b565b50831561074e576040805162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015290519081900360640190fd5b90505b92915050565b606060008213156107725761076b82610854565b9050610221565b61077e82600003610854565b60405160200180807f2d0000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b602083106107d85780518252601f1990920191602091820191016107b9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040529050610221565b60008061081e610c51565b6001600160a01b039390931660009081526039939093016020525050604090205468010000000000000000900463ffffffff1690565b60608161087957506040805180820190915260018152600360fc1b6020820152610221565b8160005b811561089157600101600a8204915061087d565b60008167ffffffffffffffff811180156108aa57600080fd5b506040519080825280601f01601f1916602001820160405280156108d5576020820181803683370190505b50859350905060001982015b831561092657600a840660300160f81b8282806001900393508151811061090457fe5b60200101906001600160f81b031916908160001a905350600a840493506108e1565b50949350505050565b60008061093a610c51565b6001600160a01b0393909316600090815260399390930160205250506040902054640100000000900463ffffffff1690565b606081516000141561098d5750604080516020810190915260008152610221565b60006040518060600160405280604081526020016154e8604091399050600060038451600201816109ba57fe5b0460040267ffffffffffffffff811180156109d457600080fd5b506040519080825280601f01601f1916602001820160405280156109ff576020820181803683370190505b509050600182016020820185865187015b80821015610a6b576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250610a10565b5050600386510660018114610a875760028114610a9a57610aa2565b603d6001830353603d6002830353610aa2565b603d60018303535b509195945050505050565b6060828203610abb81610e73565b610ac361132c565b610acc836113a2565b610ad68888611431565b604051602001806092615d89823960920185805190602001908083835b60208310610b125780518252601f199092019160209182019101610af3565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b60208310610b5a5780518252601f199092019160209182019101610b3b565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b60208310610ba25780518252601f199092019160209182019101610b83565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310610bea5780518252601f199092019160209182019101610bcb565b5181516020939093036101000a60001901801990911692169190911790527f3c2f7376673e000000000000000000000000000000000000000000000000000092019182525060408051808303601919018152600690920190529a9950505050505050505050565b600090565b6000818303600b83900b8213801590610c75575083600b0b81600b0b13155b80610c935750600083600b0b128015610c93575083600b0b81600b0b135b61074e5760405162461bcd60e51b8152600401808060200182810382526024815260200180615c166024913960400191505060405180910390fd5b600082600b0b60001415610ce457506000610751565b82600b0b600019148015610d085750600b82900b6b7fffffffffffffffffffffff19145b15610d445760405162461bcd60e51b815260040180806020018281038252602781526020018061585a6027913960400191505060405180910390fd5b6000828402905082600b0b84600b0b82600b0b81610d5e57fe5b05600b0b1461074e5760405162461bcd60e51b815260040180806020018281038252602781526020018061585a6027913960400191505060405180910390fd5b600081600b0b60001415610df9576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600b0b600019148015610e1d5750600b83900b6b7fffffffffffffffffffffff19145b15610e595760405162461bcd60e51b81526004018080602001828103825260218152602001806153ac6021913960400191505060405180910390fd5b600082600b0b84600b0b81610e6a57fe5b05949350505050565b60606000610e80836115fc565b5090506000610e9082600461164d565b9050610e9a6116b4565b610ea2611727565b610eaa611a4d565b610eb384611b1b565b610ebc88611d49565b610ec461261f565b610ecc612681565b610ed4612728565b610edc612739565b610ee46127ef565b610eec6127fb565b610ef4612807565b610efc612813565b60405160200180807f3c646566733e00000000000000000000000000000000000000000000000000008152506006018e805190602001908083835b60208310610f565780518252601f199092019160209182019101610f37565b6001836020036101000a0380198251168184511680821785525050505050509050018d805190602001908083835b60208310610fa35780518252601f199092019160209182019101610f84565b51815160209384036101000a60001901801990921691161790528f5191909301928f0191508083835b60208310610feb5780518252601f199092019160209182019101610fcc565b51815160209384036101000a60001901801990921691161790528e5191909301928e0191508083835b602083106110335780518252601f199092019160209182019101611014565b51815160209384036101000a60001901801990921691161790528d5191909301928d0191508083835b6020831061107b5780518252601f19909201916020918201910161105c565b51815160209384036101000a60001901801990921691161790528c5191909301928c0191508083835b602083106110c35780518252601f1990920191602091820191016110a4565b51815160209384036101000a60001901801990921691161790528b5191909301928b0191508083835b6020831061110b5780518252601f1990920191602091820191016110ec565b51815160209384036101000a60001901801990921691161790528a5191909301928a0191508083835b602083106111535780518252601f199092019160209182019101611134565b51815160209384036101000a600019018019909216911617905289519190930192890191508083835b6020831061119b5780518252601f19909201916020918201910161117c565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b602083106111e35780518252601f1990920191602091820191016111c4565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b6020831061122b5780518252601f19909201916020918201910161120c565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106112735780518252601f199092019160209182019101611254565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106112bb5780518252601f19909201916020918201910161129c565b6001836020036101000a038019825116818451168082178552505050505050905001807f3c2f646566733e000000000000000000000000000000000000000000000000008152506007019d505050505050505050505050505060405160208183030381529060405292505050919050565b606060405160200180806157d2602d91397f2332353333323600000000000000000000000000000000000000000000000000602d8201527f222f3e000000000000000000000000000000000000000000000000000000000060348201526040805160178184030181526037909201905291505090565b60606113ad82612890565b604051602001806054615c3a823960540182805190602001908083835b602083106113e95780518252601f1990920191602091820191016113ca565b5181516020939093036101000a6000190180199091169216919091179052631e17b39f60e11b92019182525060408051808303601b1901815260049092019052949350505050565b606061143c83612fba565b611451611448856103f6565b60f06004613062565b61145a856131dd565b61146385613320565b604051602001806041615881823960410185805190602001908083835b6020831061149f5780518252601f199092019160209182019101611480565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b602083106114e75780518252601f1990920191602091820191016114c8565b6001836020036101000a0380198251168184511680821785525050505050509050018061597a6043913960430183805190602001908083835b6020831061153f5780518252601f199092019160209182019101611520565b6001836020036101000a03801982511681845116808217855250505050505090500180615d296060913960600182805190602001908083835b602083106115975780518252601f199092019160209182019101611578565b5181516020939093036101000a60001901801990911692169190911790527f3c2f746578743e00000000000000000000000000000000000000000000000000920191825250604080518083036018190181526007909201905298975050505050505050565b60008061160e600b84900b60c861337f565b9150611626600161162084601061337f565b906133e6565b9050600061163583601061164d565b1115610310576116468160016133e6565b9050915091565b60008082116116a3576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b8183816116ac57fe5b069392505050565b6040517f3c672069643d22706c6f74223e0000000000000000000000000000000000000060208201908152606091602d01606c614ae68239606c0180615427606c9139606c0160686151328239631e17b39f60e11b606882015260408051604c818403018152606c909201905291505090565b6060611753604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b6117a0604051806040016040528060078152602001666c656166526f7760c81b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6117ed604051806040016040528060078152602001666c656166526f7760c81b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b61183a604051806040016040528060078152602001666c656166526f7760c81b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b611887604051806040016040528060078152602001666c656166526f7760c81b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b60405160200180807f3c672069643d2266756c6c4c656166506c6f74223e000000000000000000000081525060150186805190602001908083835b602083106118e15780518252601f1990920191602091820191016118c2565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b602083106119295780518252601f19909201916020918201910161190a565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b602083106119715780518252601f199092019160209182019101611952565b51815160209384036101000a600019018019909216911617905286519190930192860191508083835b602083106119b95780518252601f19909201916020918201910161199a565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611a015780518252601f1990920191602091820191016119e2565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040195505050505050604051602081830303815290604052905090565b6060611a79604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b60405160200180807f3c672069643d22656d707479506c6f74223e000000000000000000000000000081525060120182805190602001908083835b60208310611ad35780518252601f199092019160209182019101611ab4565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401915050604051602081830303815290604052905090565b606081611b715750604080517f3c672069643d227061727469616c4c656166526f77223e0000000000000000006020820152631e17b39f60e11b60378201528151601b818303018152603b909101909152610221565b8160011415611bda576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b8160021415611c4d576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b8160031415611cca576040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280160296154bf823960290180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b6040517f3c672069643d227061727469616c4c656166526f77223e00000000000000000060208201908152906037016025615258823960250160286152c3823960280160296154bf823960290180615e556029913960290180631e17b39f60e11b81525060040190506040516020818303038152906040529050610221565b60606000611d616010611620600b86900b60c861337f565b90506000611d7a6004611d74848261337f565b9061164d565b90506000611d8983600461164d565b905081612035578015611efc57611dc0604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b611e146040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b60208310611e695780518252601f199092019160209182019101611e4a565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611eb15780518252601f199092019160209182019101611e92565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612035565b611f046137aa565b611f51604051806040016040528060078152602001666c656166526f7760c81b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b60208310611fa65780518252601f199092019160209182019101611f87565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310611fee5780518252601f199092019160209182019101611fcf565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b8152506004019250505060405160208183030381529060405293505b816001141561222b5780156121885761204c6138b5565b6120a06040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106120f55780518252601f1990920191602091820191016120d6565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061213d5780518252601f19909201916020918201910161211e565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040192505050604051602081830303815290604052935061222b565b6121906138b5565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106121e55780518252601f1990920191602091820191016121c6565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b816002141561242157801561237e5761224261392e565b6122966040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106122eb5780518252601f1990920191602091820191016122cc565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106123335780518252601f199092019160209182019101612314565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612421565b61238661392e565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106123db5780518252601f1990920191602091820191016123bc565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b8160031415612617578015612574576124386137aa565b61248c6040518060400160405280600e81526020016d7061727469616c4c656166526f7760901b815250604819601560405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180183805190602001908083835b602083106124e15780518252601f1990920191602091820191016124c2565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106125295780518252601f19909201916020918201910161250a565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b815250600401925050506040516020818303038152906040529350612617565b61257c6137aa565b6040516020018080771e339034b21e913830b93a34b0b62632b0b3283637ba111f60411b81525060180182805190602001908083835b602083106125d15780518252601f1990920191602091820191016125b2565b6001836020036101000a03801982511681845116808217855250505050505090500180631e17b39f60e11b81525060040191505060405160208183030381529060405293505b505050919050565b6040517f3c672069643d226c656166223e0000000000000000000000000000000000000060208201908152606091602d01610339614b528239631e17b39f60e11b6103398201526040805161031d81840301815261033d909201905291505090565b6040517f3c672069643d2273696c6f223e0000000000000000000000000000000000000060208201908152606091602d0160be61519a823960be016101b9614f7982396101b90160ae614943823960ae01609b615c8e8239609b0160da6155d4823960da0161010a615b0c823961010a0160a4614e8b823960a401605161552882396051016101246156ae8239610124019050604051602081830303815290604052905090565b60606127346000613985565b905090565b6040517f3c672069643d224245414e33435256000000000000000000000000000000000060208201908152606091602f01603a615e1b8239603a01604a614f2f8239604a0160c16152eb823960c10160676159138239606701604661527d8239604601607b614a6b82397f3c2f6c696e6561724772616469656e743e3c2f646566733e0000000000000000607b820152631e17b39f60e11b60938201526040805160778184030181526097909201905291505090565b60606127346001613985565b60606127346000613b08565b60606127346001613b08565b6040517f3c672069643d226c656166526f77223e00000000000000000000000000000000602082019081526060916030016025615258823960250160286152c3823960280160296154bf823960290180615e5560299139631e17b39f60e11b602982015260408051600d818403018152602d909201905291505090565b60606000604051806102a001604052806040518060400160405280604419815260200160a319815250815260200160405180604001604052806045815260200160a3198152508152602001604051806040016040528060008152602001607b1981525081526020016040518060400160405280608a8152602001607b19815250815260200160405180604001604052806089198152602001607b198152508152602001604051806040016040528060441981526020016053198152508152602001604051806040016040528060458152602001605319815250815260200160405180604001604052806089198152602001602b198152508152602001604051806040016040528060008152602001602b1981525081526020016040518060400160405280608a8152602001602b198152508152602001604051806040016040528060441981526020016003198152508152602001604051806040016040528060458152602001600319815250815260200160405180604001604052806089198152602001602481525081526020016040518060400160405280608a81526020016024815250815260200160405180604001604052806044198152602001604c8152508152602001604051806040016040528060458152602001604c81525081526020016040518060400160405280608919815260200160748152508152602001604051806040016040528060008152602001607481525081526020016040518060400160405280608a815260200160748152508152602001604051806040016040528060458152602001609c815250815260200160405180604001604052806044198152602001609c81525081525090506000604051806102a001604052806014815260200160138152602001600d81526020016012815260200160158152602001600e8152602001600c8152602001600f815260200160058152602001600b81526020016006815260200160048152602001600781526020016003815260200160088152602001600281526020016010815260200160018152602001600a8152602001600981526020016011815250905060606000612baf866115fc565b91505060005b6015811015612faf576000848260158110612bcc57fe5b6020020151905082811015612ce95783612c336040518060400160405280600c81526020016b199d5b1b13195859941b1bdd60a21b815250888560158110612c1057fe5b602002015151898660158110612c2257fe5b602002015160016020020151613062565b6040516020018083805190602001908083835b60208310612c655780518252601f199092019160209182019101612c46565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612cad5780518252601f199092019160209182019101612c8e565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529350612f28565b82811415612e30578260011415612de55783612d2f6040518060400160405280600c81526020016b199d5b1b13195859941b1bdd60a21b815250888560158110612c1057fe5b6040516020018083805190602001908083835b60208310612d615780518252601f199092019160209182019101612d42565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612da95780518252601f199092019160209182019101612d8a565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529350612e2b565b83612c336040518060400160405280600f81526020017f7061727469616c4c656166506c6f740000000000000000000000000000000000815250888560158110612c1057fe5b612f28565b83612e766040518060400160405280600981526020017f656d707479506c6f740000000000000000000000000000000000000000000000815250888560158110612c1057fe5b6040516020018083805190602001908083835b60208310612ea85780518252601f199092019160209182019101612e89565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612ef05780518252601f199092019160209182019101612ed1565b6001836020036101000a0380198251168184511680821785525050505050509050019250505060405160208183030381529060405293505b81600b1415612fa657836040516020018082805190602001908083835b60208310612f645780518252601f199092019160209182019101612f45565b6001836020036101000a03801982511681845116808217855250505050505090500180614905603e9139603e0191505060405160208183030381529060405293505b50600101612bb5565b509095945050505050565b6060612fc5826103f6565b60405160200180605b6157ff8239605b0182805190602001908083835b602083106130015780518252601f199092019160209182019101612fe2565b5181516020939093036101000a60001901801990911692169190911790527f204465706f7369743c2f746578743e000000000000000000000000000000000092019182525060408051808303601019018152600f9092019052949350505050565b60608361306e84613c9f565b61307784613c9f565b6040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120184805190602001908083835b602083106130c65780518252601f1990920191602091820191016130a7565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528551600590910192860191508083835b6020831061311f5780518252601f199092019160209182019101613100565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528451600590910192850191508083835b602083106131785780518252601f199092019160209182019101613159565b5181516020939093036101000a60001901801990911692169190911790527f22202f3e0000000000000000000000000000000000000000000000000000000092019182525060408051808303601b190181526004909201905298975050505050505050565b60606131e882613cbf565b6131f183613cbf565b60405160200180605c6148a98239605c01605a6153cd8239605a0183805190602001908083835b602083106132375780518252601f199092019160209182019101613218565b5181516020939093036101000a60001901801990911692169190911790527f3c2f747370616e3e3c2f746578743e0000000000000000000000000000000000920191825250600f01605c6148a98239605c01605b6155798239605b0182805190602001908083835b602083106132be5780518252601f19909201916020918201910161329f565b5181516020939093036101000a60001901801990911692169190911790527f3c2f747370616e3e3c2f746578743e000000000000000000000000000000000092019182525060408051808303601019018152600f909201905295945050505050565b6060600082600b0b1261335357620186a082600b0b13156133475761076b82600b0b613cd5565b61076b82600b0b610854565b620186a082600003600b0b13156133735761077e82600003600b0b613cd5565b61076b82600b0b610757565b60008082116133d5576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816133de57fe5b049392505050565b60008282018381101561074e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60608361344c84613c9f565b61345584613c9f565b6040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120184805190602001908083835b602083106134a45780518252601f199092019160209182019101613485565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528551600590910192860191508083835b602083106134fd5780518252601f1990920191602091820191016134de565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528451600590910192850191508083835b602083106135565780518252601f199092019160209182019101613537565b5181516020939093036101000a60001901801990911692169190911790527f22207472616e73666f726d3d227363616c6528312e3429222f3e00000000000092019182525060408051808303600519018152601a909201905298975050505050505050565b6060846135c785613c9f565b6135d085613c9f565b846040516020018080713c75736520786c696e6b3a687265663d222360701b81525060120185805190602001908083835b602083106136205780518252601f199092019160209182019101613601565b51815160209384036101000a60001901801990921691161790526411103c1e9160d91b919093019081528651600590910192870191508083835b602083106136795780518252601f19909201916020918201910161365a565b51815160209384036101000a60001901801990921691161790526411103c9e9160d91b919093019081528551600590910192860191508083835b602083106136d25780518252601f1990920191602091820191016136b3565b51815160209384036101000a60001901801990921691161790527f222066696c6c3d22000000000000000000000000000000000000000000000000919093019081528451600890910192850191508083835b602083106137435780518252601f199092019160209182019101613724565b5181516020939093036101000a60001901801990911692169190911790527f22207472616e73666f726d3d227363616c6528312e3429222f3e00000000000092019182525060408051808303600519018152601a90920190529a9950505050505050505050565b60606137b461392e565b613801604051806040016040528060078152602001666c656166526f7760c81b815250603b19600e604051806040016040528060078152602001662341384338334160c81b8152506135bb565b6040516020018083805190602001908083835b602083106138335780518252601f199092019160209182019101613814565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b6020831061387b5780518252601f19909201916020918201910161385c565b6001836020036101000a03801982511681845116808217855250505050505090500192505050604051602081830303815290604052905090565b60606138e1604051806040016040528060048152602001631c1b1bdd60e21b8152506022196000613440565b613801604051806040016040528060078152602001666c656166526f7760c81b8152506022196000604051806040016040528060078152602001662341384338334160c81b8152506135bb565b60606139386138b5565b613801604051806040016040528060078152602001666c656166526f7760c81b815250602e19600760405180604001604052806007815260200166119c1ca09b192360c91b8152506135bb565b6060816139ae57604051806040016040528060048152602001632122a0a760e11b8152506139ce565b604051806040016040528060068152602001653ab92122a0a760d11b8152505b826139f857604051806040016040528060078152602001662334364239353560c81b815250613a19565b604051806040016040528060078152602001662337463535333360c81b8152505b6040516020018080661e339034b21e9160c91b81525060070183805190602001908083835b60208310613a5d5780518252601f199092019160209182019101613a3e565b6001836020036101000a03801982511681845116808217855250505050505090500180615493602c9139602c0182805190602001908083835b60208310613ab55780518252601f199092019160209182019101613a96565b6001836020036101000a038019825116818451168082178552505050505050905001806149f1607a9139631e17b39f60e11b607a82015260408051808303605e018152607e909201905295945050505050565b606081613b3457604051806040016040528060078152602001660848a829c8aa8960cb1b815250613b57565b604051806040016040528060098152602001680eae4848a829c8aa8960bb1b8152505b82613b8157604051806040016040528060078152602001662334364239353560c81b815250613ba2565b604051806040016040528060078152602001662337463535333360c81b8152505b6040516020018080661e339034b21e9160c91b81525060070183805190602001908083835b60208310613be65780518252601f199092019160209182019101613bc7565b6001836020036101000a03801982511681845116808217855250505050505090500180615493602c9139602c0182805190602001908083835b60208310613c3e5780518252601f199092019160209182019101613c1f565b6001836020036101000a038019825116818451168082178552505050505050905001806158c26051913960510161014f6159bd8239631e17b39f60e11b61014f82015260408051808303610133018152610153909201905295945050505050565b60606000821215613cb65761077e82600003610854565b61076b82610854565b60606107516001600160a01b03831660146105c6565b6060620f4240821015613ced5761076b826005613f40565b62989680821015613d035761076b826006613f40565b6305f5e100821015613d1a5761076b826007613f40565b633b9aca00821015613d315761076b826008613f40565b6402540be400821015613d495761076b826009613f40565b64174876e800821015613d615761076b82600a613f40565b64e8d4a51000821015613d795761076b82600b613f40565b6509184e72a000821015613d925761076b82600c613f40565b655af3107a4000821015613dab5761076b82600d613f40565b66038d7ea4c68000821015613dc55761076b82600e613f40565b662386f26fc10000821015613ddf5761076b82600f613f40565b67016345785d8a0000821015613dfa5761076b826010613f40565b670de0b6b3a7640000821015613e155761076b826011613f40565b678ac7230489e80000821015613e305761076b826012613f40565b68056bc75e2d63100000821015613e4c5761076b826013613f40565b683635c9adc5dea00000821015613e685761076b826014613f40565b69021e19e0c9bab2400000821015613e855761076b826015613f40565b69152d02c7e14af6800000821015613ea25761076b826016613f40565b69d3c21bcecceda1000000821015613ebf5761076b826017613f40565b6a084595161401484a000000821015613edd5761076b826018613f40565b6a52b7d2dcc80cd2e4000000821015613efb5761076b826019613f40565b6b033b2e3c9fd0803ce8000000821015613f1a5761076b82601a613f40565b6b204fce5e3e25026110000000821015613f395761076b82601b613f40565b61076b82601c5b6060613f5361016484600a85900a61337f565b613f75610164620186a0611d74613f6b8760056140d8565b8890600a0a61337f565b613f7e84610854565b6040516020018084805190602001908083835b60208310613fb05780518252601f199092019160209182019101613f91565b6001836020036101000a038019825116818451168082178552505050505050905001807f2e0000000000000000000000000000000000000000000000000000000000000081525060010183805190602001908083835b602083106140255780518252601f199092019160209182019101614006565b6001836020036101000a038019825116818451168082178552505050505050905001807f650000000000000000000000000000000000000000000000000000000000000081525060010182805190602001908083835b6020831061409a5780518252601f19909201916020918201910161407b565b6001836020036101000a0380198251168184511680821785525050505050509050019350505050604051602081830303815290604052905092915050565b60008282111561412f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b8035600b81900b811461022157600080fd5b60008060006060848603121561415b578283fd5b83356001600160a01b0381168114614171578384fd5b925061417f60208501614135565b915061418d60408501614135565b90509250925092565b6000602082840312156141a7578081fd5b5035919050565b600081516141c0818560208601614878565b9290920192915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815260010190565b7f7d2c207b202274726169745f74797065223a202267726f776e207374616c6b2081527f70657220424456222c2022646973706c61795f74797065223a20226e756d626560208201527f72222c202276616c7565223a20000000000000000000000000000000000000006040820152604d0190565b7f227d2c207b202274726169745f74797065223a20227374656d222c202264697381527f706c61795f74797065223a20226e756d626572222c202276616c7565223a20006020820152603f0190565b7f7d2c207b202274726169745f74797065223a2022696e6974616c207374616c6b81527f2070657220424456222c2022646973706c61795f74797065223a20226e756d6260208201527f6572222c202276616c7565223a200000000000000000000000000000000000006040820152604e0190565b7f7d2c207b202274726169745f74797065223a20227374616c6b2067726f776e2081527f706572204244562070657220736561736f6e222c2022646973706c61795f747960208201527f7065223a20226e756d626572222c202276616c7565223a200000000000000000604082015260580190565b60007f2c202261747472696275746573223a205b207b202274726169745f747970652282527f3a2022546f6b656e222c202276616c7565223a20220000000000000000000000602083015288516143ff816035850160208d01614878565b7f227d2c207b202274726169745f74797065223a2022546f6b656e2041646472656035918401918201527f7373222c202276616c7565223a2022000000000000000000000000000000000060558201528851614462816064840160208d01614878565b7f227d2c207b202274726169745f74797065223a20224964222c202276616c7565606492909101918201527f223a202200000000000000000000000000000000000000000000000000000000608482015287516144c6816088840160208c01614878565b61451061450a6145056144ff6144fa6144f46144ef6144e96088898b0101614268565b8f6141ae565b6142b7565b8c6141ae565b6141f3565b896141ae565b61432c565b866141ae565b9b9a5050505050505050505050565b60007f2c2022696d616765223a202200000000000000000000000000000000000000008252825161455781600c850160208701614878565b7f2200000000000000000000000000000000000000000000000000000000000000600c939091019283015250600d01919050565b60007f7b0000000000000000000000000000000000000000000000000000000000000082527f226e616d65223a20224265616e7374616c6b2053696c6f204465706f7369747360018301527f222c20226465736372697074696f6e223a2022416e204552433131353520726560218301527f70726573656e74696e6720616e206173736574206465706f736974656420696e60418301527f20746865204265616e7374616c6b2053696c6f2e2053696c6f204465706f736960618301527f7473206761696e207374616c6b20616e64206265616e20736569676e6f72616760818301527f652e20000000000000000000000000000000000000000000000000000000000060a18301527f5c6e5c6e444953434c41494d45523a204475652064696c6967656e636520697360a48301527f20696d7065726174697665207768656e20617373657373696e6720746869732060c48301527f4e46542e204f70656e73656120616e64206f74686572204e4654206d61726b6560e48301527f74706c616365732063616368652074686520737667206f757470757420616e646101048301527f20746875732c206d6179207265717569726520746865207573657220746f20726101248301527f65667265736820746865206d6574616461746120746f2070726f7065726c79206101448301527f73686f772074686520636f72726563742076616c7565732e22000000000000006101648301526147c16147bc6147b661017d8501876141ae565b856141ae565b6141ca565b949350505050565b60007f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008252825161480181601d850160208701614878565b91909101601d0192915050565b600060208252825180602084015261482d816040850160208701614878565b601f01601f19169190910160400192915050565b6020808252601d908201527f53696c6f3a206d6574616461746120646f6573206e6f74206578697374000000604082015260600190565b60005b8381101561489357818101518382015260200161487b565b838111156148a2576000848401525b5050505056fe3c7465787420783d223132372220793d223334332220666f6e742d73697a653d223130222066696c6c3d2257686974652220746578742d616e63686f723d226d6964646c652220666f6e742d66616d696c793d22667574757261223e3c75736520786c696e6b3a687265663d222373696c6f2220783d2234372220793d22353522207472616e73666f726d3d227363616c6528312e3729222f3e3c7061746820643d224d35372e34382031392e3438324335372e36343520392e32342034342e3937382e3732372032392e3138372e3436382031332e3339372e32312e34363320382e3330332e3239382031382e3534362e3133342032382e3738382031322e382033372e332032382e3539312033372e35366331352e37392e3235382032382e3732342d372e3833352032382e3838392d31382e3037385a222066696c6c3d2223434343222f3e222f3e3c7061746820643d226d372e36383720312e3236352d332e35303420392e3336532e32393820332e39393920372e36383720312e3236365a6d2d322e36393120382e373820322e3436322d362e36393173342e35333820332e36372d322e34363220362e3639315a222066696c6c3d2223666666222f3e3c73746f70206f66667365743d222e353136222073746f702d636f6c6f723d2223463046353037222f3e3c73746f70206f66667365743d222e373334222073746f702d636f6c6f723d2223383543443735222f3e3c73746f70206f66667365743d2231222073746f702d636f6c6f723d2223303239444642222f3e3c7061746820643d224d37392e35373238203132392e3236354c3132372e343639203135362e3833334c3137352e343433203132392e3234354c3132372e343639203130312e3639374c37392e35373238203132392e3236355a222066696c6c3d2223393434413237222f3e3c7061746820643d224d3137312e383834203131382e39383361342e39333220342e3933322030203020312d312e30313820322e36303620342e37313520342e3731352030203020312d312e38373820312e343339632d2e3436352e3139352d312e3733352e3732372d322e3336342e3137362d2e32343620332e3239382d312e35393320362e3531322d322e32353320372e39353461342e35333220342e3533322030203020312d2e3331332d2e393333632d2e3231312d2e3937352d2e3033382d312e3736332e3037382d322e3239352e3230322d2e3932312e3335332d312e3631322e3436372d322e31342d312e3137372e3639342d322e3634322e3536392d332e3535382d2e3237322d2e3739362d2e3733322d312e3038332d312e3932312d2e3734332d332e3033342e3439382e30313120312e3933392e31303920332e32343720312e31363761352e313320352e313320302030203120312e323120312e343133632e3135392d2e37342e3139392d2e3935382e3233382d312e3137392e3230392d312e3231332e3332322d312e3837322e3237342d322e37323461372e373320372e37332030203020302d2e3930382d332e313737632d2e3737322e3431352d312e3738392e3139362d322e3337382d2e3330342d2e3333392d2e3238372d2e3535362d2e3638322d2e3736342d312e3639326131322e3733392031322e3733392030203020312d2e3137362d332e393039632e3738392e36303320312e343720312e30313920312e39333720312e3238332e3934342e35333620312e3334342e36333920312e37363120312e3136372e3135322e3139332e3634392e3834322e35383620312e3735312d2e3031312e3137322d2e3035332e3739352d2e34363420312e32393361362e383320362e383320302030203120312e33383420322e323237632e31342e3336382e3234322e3734342e33313120312e31352e3130372d2e3230372e3236312d2e3433392e3531312d2e3732322e3435332d2e3531332e38372d2e39393220312e3630342d312e3238342e3638332d2e32373220312e32382d2e32343920312e3732332d2e32333461352e33303220352e33303220302030203120312e3438362e3237335a222f3e3c70617468206f7061636974793d222e34342220643d224d312e38312032362e353332632e3230362e3439342e34383420312e30352e383620312e36336131302e3236362031302e32363620302030203020322e32373820322e3438364c362e3535322037382e32326131372e3237322031372e3237322030203020312d332d372e3431334c312e38312032362e3533325a222066696c6c3d2223453645364536222f3e222f3e3c7061746820643d226d372e36383720312e3736342d332e35303420392e3336532e32393820342e34393920372e36383720312e3736355a222066696c6c3d2223666666222f3e3c7061746820643d224d2e3436342031392e353434632e3639392031362e35383520312e342033332e31363920322e3039382034392e3735322e30323120322e3338312e343820342e3237382e38383320352e3533392e3237372e38362e37343120322e32373520312e37373820332e3836372e3439342e37353920312e32313220312e3720332e30303220332e33333220312e37333920312e35383620332e333520332e30353620352e37333220342e33393820332e32393320312e38353520362e31353120322e33393620382e37393120322e38393620312e3835352e333520352e3134392e39343820392e3438382e3535366133322e3730372033322e37303720302030203020392e3331352d322e32383763312e3836322d2e37353920342e3634322d312e39313720372e3633332d342e3420312e3334382d312e313220332e3434382d322e38393720352e3139372d352e39356132302e3131342032302e31313420302030203020322e32352d352e393938632e32312d31372e3535322e34322d33352e3130342e3633322d35322e3635376c2d35362e382e393532682e3030315a222066696c6c3d2223423342334233222f3e3c7061746820643d224d3137352e343637203133332e344c3137352e343433203132392e3234354c3132372e343639203135362e3833334c3132372e353037203136302e3930384c3137352e343637203133332e345a222066696c6c3d2223363733333145222f3e3c7061746820643d224d35372e3130382037312e3239632e3138382d31312e3635332d31322e30312d32312e3330332d32372e3234332d32312e3535322d31352e3233342d2e32352d32372e37333620382e3939352d32372e3932332032302e3634392d2e3138372031312e3635342031322e30312032312e3330342032372e3234342032312e3535332031352e3233332e32352032372e3733352d382e3939352032372e3932322d32302e36355a222066696c6c3d2223363636222f3e3c75736520786c696e6b3a687265663d22236c6561662220783d22302220793d2230222f3e3c73746f702073746f702d636f6c6f723d2223383230323032222f3e3c73746f70206f66667365743d222e313832222073746f702d636f6c6f723d2223463731453035222f3e3c75736520786c696e6b3a687265663d22236c6561662220783d222d31322220793d222d37222f3e3c7061746820643d224d382e31333220382e303738632d2e3436362e36342d312e32393720312e3332332d322e36393520312e3939326c322e3132362d352e373737632e3038392e30392e3139332e3230342e332e3333382e3330332e3337352e3632352e3839312e37343420312e3438342e3131372e3538332e303420312e3235332d2e34373520312e3936335a222066696c6c3d2275726c2823612922207374726f6b653d222366666622207374726f6b652d77696474683d222e35222f3e5369676e6564536166654d6174683a206469766973696f6e206f766572666c6f773c747370616e3e3c616e696d617465206174747269627574654e616d653d2278222066726f6d3d223337352220746f3d22353022206475723d223130732220726570656174436f756e743d22696e646566696e69746522202f3e3c7061746820643d224d37392e35333332203133332e3432364c37392e35373237203132392e3236354c3132372e343639203135362e3833334c3132372e353037203136302e3930384c37392e35333332203133332e3432365a222066696c6c3d2223373533393146222f3e223e3c726563742077696474683d22313222206865696768743d223132222072783d2236222066696c6c3d223c75736520786c696e6b3a687265663d22236c6561662220783d222d32342220793d222d3134222f3e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f3c7061746820643d226d33332e3039322034392e3434312d362e3338312031352e323131732d362e3037382d31312e31353920362e3338312d31352e32315a222066696c6c3d2223384538453845222f3e3c747370616e3e3c616e696d617465206174747269627574654e616d653d2278222066726f6d3d2235302220746f3d222d32373522206475723d223130732220726570656174436f756e743d22696e646566696e69746522202f3e3c7061746820643d224d362e3431342032382e38396131352e3737372031352e3737372030203020312d322e3039332d322e313436632d2e3835362d312e3036332d322e3435332d332e3039332d322e3937352d362e3131326131312e3736352031312e3736352030203020312d2e3039332d332e3330376c32352e34332d392e393736632e3034332e3134322e3138382e3535352e3630342e3836382e34362e3334362e3934372e333420312e3038362e3333344c362e3431332032382e383838762e3030325a222066696c6c3d2223453645364536222f3e3c7061746820643d226d32362e3732352036342e3835382d2e3039312d2e313735632d2e3032362d2e3034392d322e3633342d342e3932332d2e3836372d392e333720312e3035372d322e37313720332e3531382d342e37323520372e332d352e3934366c2e3138372d2e3036312d362e35332031352e3535325a6d362e3231322d31352e323638632d332e36323120312e3231372d352e39393120332e3136382d372e30323220352e3739382d312e35333820332e3930382e33353520382e3136362e37383820392e3035346c362e3233342d31342e3835325a4d32382e3039332036332e3733376c342e3438342d31302e383773372e33363520362e3333372d342e3438342031302e38375a222066696c6c3d2223384538453845222f3e3c2f673e3c726563742077696474683d2232353522206865696768743d22333530222072783d223130222066696c6c3d223c7465787420783d2231302220793d2231342e352220666f6e742d73697a653d223132222066696c6c3d2257686974652220746578742d616e63686f723d2273746172742220666f6e742d66616d696c793d22667574757261223e5369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f773c7265637420783d22302220793d2230222077696474683d2232353522206865696768743d223230222072783d2235222066696c6c3d2223323432343234222f3e222f3e3c7061746820643d226d372e36383420312e3236352d332e35303520392e3336632e30303320302d332e3838342d362e36323520332e3530352d392e33365a222066696c6c3d2223666666222f3e3c646566733e3c6c696e6561724772616469656e742069643d2261222078313d22362e3935222079313d22332e383533222078323d22362e3935222079323d2231302e35343422206772616469656e74556e6974733d227573657253706163654f6e557365223e3c7265637420783d22302220793d22333330222077696474683d2232353522206865696768743d223230222072783d2235222066696c6c3d2223323432343234222f3e3c7061746820643d224d382e39353220362e393836612e3036332e3036332030203020312d2e3032322e303033632d2e37312e31332d312e3432342e3235352d322e3133342e3338312d2e3238312e3035322d2e3536352e3130332d2e3834362e313532612e3033362e3033362030203020312d2e30323620306c322e31342d352e3632352e3030342d2e303033632e32393720312e3730322e353920332e3339342e38383420352e3039325a6d2d2e3138372e343738632d312e3236362e3835392d322e35333120312e3732312d332e3820322e35386c2e3738312d322e303534632e3030372e3030342e3031332030202e3032332030202e3735392d2e31333220312e3531342d2e32363820322e32372d2e346c2e3639372d2e3132362e30332d2e303036632d2e3030342e3030332030202e3030362030202e3030365a222066696c6c3d2223303030222f3e3c70617468206f7061636974793d222e33332220643d224d312e3437372031362e303239632e32352d2e3933312e3730362d322e32353820312e35372d332e3639352e3635352d312e30393220312e3239322d312e38323520312e37362d322e3335382e3538342d2e36363520312e3737362d312e39333420332e3637392d332e323920322e3935332d322e31303520352e3639362d332e303520372e3732332d332e37336133372e33352033372e333520302030203120362e3438352d312e3534376c352e32343220342e33313661312e343820312e34382030203020302d312e3231342e3936374c312e34382031362e3033682d2e3030325a222066696c6c3d2223393939222f3e5369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f773c75736520786c696e6b3a687265663d222373696c6f2220783d2239392220793d223535222f3e3c672069643d22616c6c506c6f742220636c69702d706174683d2275726c2823626f726465724d61736b29223e3c7061746820643d224d33302e33313420372e313337632e3030392d2e3536312d2e36382d312e3032382d312e3533382d312e3034322d2e3835392d2e3031342d312e3536322e34332d312e3537312e3939312d2e30312e3536322e363820312e30323820312e35333820312e3034322e3835392e30313520312e3536322d2e343320312e35372d2e39395a222066696c6c3d2223363636222f3e3c7465787420783d223233352220793d2231342e352220666f6e742d73697a653d223132222066696c6c3d2257686974652220746578742d616e63686f723d22656e642220666f6e742d66616d696c793d22667574757261223e5374656d3a203c73766720636c6173733d22737667426f6479222077696474683d2232353522206865696768743d22333530222076696577426f783d2230203020323535203335302220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b223e223e3c7265637420793d222e35222077696474683d22313222206865696768743d223132222072783d2236222066696c6c3d22233436423935353c75736520786c696e6b3a687265663d22236c6561662220783d222d33362220793d222d3231222f3ea2646970667358221220dc0a0dfe5561279103de1e337f625a3294dd4c3482bde66c9d10efa5c65a279e64736f6c63430007060033

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

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.