ETH Price: $3,547.32 (+0.51%)
Gas: 4 Gwei

Contract

0x9c9360C85cd020D4eF38775F6ADEdD38931f1731
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60806040171275432023-04-26 2:50:35417 days ago1682477435IN
 Create: SeasonFacet
0 ETH0.1300808634.93637156

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SeasonFacet

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 44 : SeasonFacet.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "contracts/libraries/Token/LibTransfer.sol";
import "contracts/libraries/LibIncentive.sol";
import "./Weather.sol";

/**
 * @title SeasonFacet
 * @author Publius, Chaikitty
 * @notice Holds the Sunrise function and handles all logic for Season changes.
 */
contract SeasonFacet is Weather {
    using SafeMath for uint256;

    /**
     * @notice Emitted when the Season changes.
     * @param season The new Season number
     */
    event Sunrise(uint256 indexed season);

    /**
     * @notice Emitted when Beanstalk pays `beans` to `account` as a reward for calling `sunrise()`.
     * @param account The address to which the reward Beans were sent
     * @param beans The amount of Beans paid as a reward
     */
    event Incentivization(address indexed account, uint256 beans);

    //////////////////// SUNRISE ////////////////////

    /**
     * @notice Advances Beanstalk to the next Season, sending reward Beans to the caller's circulating balance.
     * @return reward The number of beans minted to the caller.
     */
    function sunrise() external payable returns (uint256) {
        return gm(msg.sender, LibTransfer.To.EXTERNAL);
    }

    /**
     * @notice Advances Beanstalk to the next Season, sending reward Beans to a specified address & balance.
     * @param account Indicates to which address reward Beans should be sent
     * @param mode Indicates whether the reward beans are sent to internal or circulating balance
     * @return reward The number of Beans minted to the caller.
     */
    function gm(
        address account,
        LibTransfer.To mode
    ) public payable returns (uint256) {
        uint256 initialGasLeft = gasleft();

        require(!paused(), "Season: Paused.");
        require(seasonTime() > season(), "Season: Still current Season.");

        stepSeason();
        (int256 deltaB, uint256[2] memory balances) = stepOracle();
        uint256 caseId = stepWeather(deltaB);
        stepSun(deltaB, caseId);

        return incentivize(account, initialGasLeft, balances, mode);
    }

    //////////////////// SEASON GETTERS ////////////////////

    /**
     * @notice Returns the current Season number.
     */
    function season() public view returns (uint32) {
        return s.season.current;
    }

    /**
     * @notice Returns whether Beanstalk is Paused. When Paused, the `sunrise()` function cannot be called.
     */
    function paused() public view returns (bool) {
        return s.paused;
    }

    /**
     * @notice Returns the Season struct. See {Storage.Season}.
     */
    function time() external view returns (Storage.Season memory) {
        return s.season;
    }

    /**
     * @notice Returns whether Beanstalk started this Season above or below peg.
     */
    function abovePeg() external view returns (bool) {
        return s.season.abovePeg;
    }

    /**
     * @notice Returns the block during which the current Season started.
     */
    function sunriseBlock() external view returns (uint32){
        return s.season.sunriseBlock;
    }

    /**
     * @notice Returns the expected Season number given the current block timestamp.
     * {sunrise} can be called when `seasonTime() > season()`.
     */
    function seasonTime() public view virtual returns (uint32) {
        if (block.timestamp < s.season.start) return 0;
        if (s.season.period == 0) return type(uint32).max;
        return uint32((block.timestamp - s.season.start) / s.season.period); // Note: SafeMath is redundant here.
    }

    //////////////////// SEASON INTERNAL ////////////////////

    /**
     * @dev Moves the Season forward by 1.
     */
    function stepSeason() private {
        s.season.timestamp = block.timestamp;
        s.season.current += 1;
        s.season.sunriseBlock = uint32(block.number); // Note: Will overflow in the year 3650.
        emit Sunrise(season());
    }

    /**
     * @param account The address to which the reward beans are sent, may or may not
     * be the same as the caller of `sunrise()`
     * @param initialGasLeft The amount of gas left at the start of the transaction
     * @param balances The current balances of the BEAN:3CRV pool returned by {stepOracle}
     * @param mode Send reward beans to Internal or Circulating balance
     * @dev Mints Beans to `account` as a reward for calling {sunrise()}.
     */
    function incentivize(
        address account,
        uint256 initialGasLeft,
        uint256[2] memory balances,
        LibTransfer.To mode
    ) private returns (uint256) {
        // Number of blocks the sunrise is late by
        // Assumes that each block timestamp is exactly `C.BLOCK_LENGTH_SECONDS` apart.
        uint256 blocksLate = block.timestamp.sub(
            s.season.start.add(s.season.period.mul(season()))
        )
        .div(C.BLOCK_LENGTH_SECONDS);
        
        uint256 incentiveAmount = LibIncentive.determineReward(initialGasLeft, balances, blocksLate);

        LibTransfer.mintToken(C.bean(), incentiveAmount, account, mode);
        
        emit Incentivization(account, incentiveAmount);
        return incentiveAmount;
    }


}

File 2 of 44 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

File 3 of 44 : 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 4 of 44 : 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 5 of 44 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 6 of 44 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 7 of 44 : 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 8 of 44 : 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 9 of 44 : IUniswapV3Pool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import './pool/IUniswapV3PoolImmutables.sol';
import './pool/IUniswapV3PoolState.sol';
import './pool/IUniswapV3PoolDerivedState.sol';
import './pool/IUniswapV3PoolActions.sol';
import './pool/IUniswapV3PoolOwnerActions.sol';
import './pool/IUniswapV3PoolEvents.sol';

/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
    IUniswapV3PoolImmutables,
    IUniswapV3PoolState,
    IUniswapV3PoolDerivedState,
    IUniswapV3PoolActions,
    IUniswapV3PoolOwnerActions,
    IUniswapV3PoolEvents
{

}

File 10 of 44 : IUniswapV3PoolActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissionless pool actions
/// @notice Contains pool methods that can be called by anyone
interface IUniswapV3PoolActions {
    /// @notice Sets the initial price for the pool
    /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
    /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96
    function initialize(uint160 sqrtPriceX96) external;

    /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position
    /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback
    /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
    /// on tickLower, tickUpper, the amount of liquidity, and the current price.
    /// @param recipient The address for which the liquidity will be created
    /// @param tickLower The lower tick of the position in which to add liquidity
    /// @param tickUpper The upper tick of the position in which to add liquidity
    /// @param amount The amount of liquidity to mint
    /// @param data Any data that should be passed through to the callback
    /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
    /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
    function mint(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount,
        bytes calldata data
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Collects tokens owed to a position
    /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
    /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
    /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
    /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
    /// @param recipient The address which should receive the fees collected
    /// @param tickLower The lower tick of the position for which to collect fees
    /// @param tickUpper The upper tick of the position for which to collect fees
    /// @param amount0Requested How much token0 should be withdrawn from the fees owed
    /// @param amount1Requested How much token1 should be withdrawn from the fees owed
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(
        address recipient,
        int24 tickLower,
        int24 tickUpper,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);

    /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
    /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
    /// @dev Fees must be collected separately via a call to #collect
    /// @param tickLower The lower tick of the position for which to burn liquidity
    /// @param tickUpper The upper tick of the position for which to burn liquidity
    /// @param amount How much liquidity to burn
    /// @return amount0 The amount of token0 sent to the recipient
    /// @return amount1 The amount of token1 sent to the recipient
    function burn(
        int24 tickLower,
        int24 tickUpper,
        uint128 amount
    ) external returns (uint256 amount0, uint256 amount1);

    /// @notice Swap token0 for token1, or token1 for token0
    /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback
    /// @param recipient The address to receive the output of the swap
    /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0
    /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
    /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
    /// value after the swap. If one for zero, the price cannot be greater than this value after the swap
    /// @param data Any data to be passed through to the callback
    /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
    /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
    function swap(
        address recipient,
        bool zeroForOne,
        int256 amountSpecified,
        uint160 sqrtPriceLimitX96,
        bytes calldata data
    ) external returns (int256 amount0, int256 amount1);

    /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
    /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback
    /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling
    /// with 0 amount{0,1} and sending the donation amount(s) from the callback
    /// @param recipient The address which will receive the token0 and token1 amounts
    /// @param amount0 The amount of token0 to send
    /// @param amount1 The amount of token1 to send
    /// @param data Any data to be passed through to the callback
    function flash(
        address recipient,
        uint256 amount0,
        uint256 amount1,
        bytes calldata data
    ) external;

    /// @notice Increase the maximum number of price and liquidity observations that this pool will store
    /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to
    /// the input observationCardinalityNext.
    /// @param observationCardinalityNext The desired minimum number of observations for the pool to store
    function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}

File 11 of 44 : IUniswapV3PoolDerivedState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that is not stored
/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the
/// blockchain. The functions here may have variable gas costs.
interface IUniswapV3PoolDerivedState {
    /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
    /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
    /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
    /// you must call it with secondsAgos = [3600, 0].
    /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
    /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
    /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
    /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
    /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
    /// timestamp
    function observe(uint32[] calldata secondsAgos)
        external
        view
        returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);

    /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
    /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
    /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
    /// snapshot is taken and the second snapshot is taken.
    /// @param tickLower The lower tick of the range
    /// @param tickUpper The upper tick of the range
    /// @return tickCumulativeInside The snapshot of the tick accumulator for the range
    /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range
    /// @return secondsInside The snapshot of seconds per liquidity for the range
    function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)
        external
        view
        returns (
            int56 tickCumulativeInside,
            uint160 secondsPerLiquidityInsideX128,
            uint32 secondsInside
        );
}

File 12 of 44 : IUniswapV3PoolEvents.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Events emitted by a pool
/// @notice Contains all events emitted by the pool
interface IUniswapV3PoolEvents {
    /// @notice Emitted exactly once by a pool when #initialize is first called on the pool
    /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize
    /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96
    /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
    event Initialize(uint160 sqrtPriceX96, int24 tick);

    /// @notice Emitted when liquidity is minted for a given position
    /// @param sender The address that minted the liquidity
    /// @param owner The owner of the position and recipient of any minted liquidity
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity minted to the position range
    /// @param amount0 How much token0 was required for the minted liquidity
    /// @param amount1 How much token1 was required for the minted liquidity
    event Mint(
        address sender,
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted when fees are collected by the owner of a position
    /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
    /// @param owner The owner of the position for which fees are collected
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount0 The amount of token0 fees collected
    /// @param amount1 The amount of token1 fees collected
    event Collect(
        address indexed owner,
        address recipient,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount0,
        uint128 amount1
    );

    /// @notice Emitted when a position's liquidity is removed
    /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
    /// @param owner The owner of the position for which liquidity is removed
    /// @param tickLower The lower tick of the position
    /// @param tickUpper The upper tick of the position
    /// @param amount The amount of liquidity to remove
    /// @param amount0 The amount of token0 withdrawn
    /// @param amount1 The amount of token1 withdrawn
    event Burn(
        address indexed owner,
        int24 indexed tickLower,
        int24 indexed tickUpper,
        uint128 amount,
        uint256 amount0,
        uint256 amount1
    );

    /// @notice Emitted by the pool for any swaps between token0 and token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the output of the swap
    /// @param amount0 The delta of the token0 balance of the pool
    /// @param amount1 The delta of the token1 balance of the pool
    /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96
    /// @param liquidity The liquidity of the pool after the swap
    /// @param tick The log base 1.0001 of price of the pool after the swap
    event Swap(
        address indexed sender,
        address indexed recipient,
        int256 amount0,
        int256 amount1,
        uint160 sqrtPriceX96,
        uint128 liquidity,
        int24 tick
    );

    /// @notice Emitted by the pool for any flashes of token0/token1
    /// @param sender The address that initiated the swap call, and that received the callback
    /// @param recipient The address that received the tokens from flash
    /// @param amount0 The amount of token0 that was flashed
    /// @param amount1 The amount of token1 that was flashed
    /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
    /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
    event Flash(
        address indexed sender,
        address indexed recipient,
        uint256 amount0,
        uint256 amount1,
        uint256 paid0,
        uint256 paid1
    );

    /// @notice Emitted by the pool for increases to the number of observations that can be stored
    /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index
    /// just before a mint/swap/burn.
    /// @param observationCardinalityNextOld The previous value of the next observation cardinality
    /// @param observationCardinalityNextNew The updated value of the next observation cardinality
    event IncreaseObservationCardinalityNext(
        uint16 observationCardinalityNextOld,
        uint16 observationCardinalityNextNew
    );

    /// @notice Emitted when the protocol fee is changed by the pool
    /// @param feeProtocol0Old The previous value of the token0 protocol fee
    /// @param feeProtocol1Old The previous value of the token1 protocol fee
    /// @param feeProtocol0New The updated value of the token0 protocol fee
    /// @param feeProtocol1New The updated value of the token1 protocol fee
    event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);

    /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner
    /// @param sender The address that collects the protocol fees
    /// @param recipient The address that receives the collected protocol fees
    /// @param amount0 The amount of token0 protocol fees that is withdrawn
    /// @param amount0 The amount of token1 protocol fees that is withdrawn
    event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);
}

File 13 of 44 : IUniswapV3PoolImmutables.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
    /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
    /// @return The contract address
    function factory() external view returns (address);

    /// @notice The first of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token0() external view returns (address);

    /// @notice The second of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token1() external view returns (address);

    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
    /// @return The fee
    function fee() external view returns (uint24);

    /// @notice The pool tick spacing
    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
    /// This value is an int24 to avoid casting even though it is always positive.
    /// @return The tick spacing
    function tickSpacing() external view returns (int24);

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);
}

File 14 of 44 : IUniswapV3PoolOwnerActions.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Permissioned pool actions
/// @notice Contains pool methods that may only be called by the factory owner
interface IUniswapV3PoolOwnerActions {
    /// @notice Set the denominator of the protocol's % share of the fees
    /// @param feeProtocol0 new protocol fee for token0 of the pool
    /// @param feeProtocol1 new protocol fee for token1 of the pool
    function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;

    /// @notice Collect the protocol fee accrued to the pool
    /// @param recipient The address to which collected protocol fees should be sent
    /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1
    /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0
    /// @return amount0 The protocol fee collected in token0
    /// @return amount1 The protocol fee collected in token1
    function collectProtocol(
        address recipient,
        uint128 amount0Requested,
        uint128 amount1Requested
    ) external returns (uint128 amount0, uint128 amount1);
}

File 15 of 44 : IUniswapV3PoolState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
    /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
    /// when accessed externally.
    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.
    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
    /// boundary.
    /// observationIndex The index of the last oracle observation that was written,
    /// observationCardinality The current maximum number of observations stored in the pool,
    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
    /// feeProtocol The protocol fee for both tokens of the pool.
    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
    /// unlocked Whether the pool is currently locked to reentrancy
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );

    /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal0X128() external view returns (uint256);

    /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal1X128() external view returns (uint256);

    /// @notice The amounts of token0 and token1 that are owed to the protocol
    /// @dev Protocol fees will never exceed uint128 max in either token
    function protocolFees() external view returns (uint128 token0, uint128 token1);

    /// @notice The currently in range liquidity available to the pool
    /// @dev This value has no relationship to the total liquidity across all ticks
    function liquidity() external view returns (uint128);

    /// @notice Look up information about a specific tick in the pool
    /// @param tick The tick to look up
    /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
    /// tick upper,
    /// liquidityNet how much liquidity changes when the pool price crosses the tick,
    /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
    /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
    /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
    /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
    /// secondsOutside the seconds spent on the other side of the tick from the current tick,
    /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.
    /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
    /// In addition, these values are only relative and must be used only in comparison to previous snapshots for
    /// a specific position.
    function ticks(int24 tick)
        external
        view
        returns (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            int56 tickCumulativeOutside,
            uint160 secondsPerLiquidityOutsideX128,
            uint32 secondsOutside,
            bool initialized
        );

    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information
    function tickBitmap(int16 wordPosition) external view returns (uint256);

    /// @notice Returns the information about a position by the position's key
    /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper
    /// @return _liquidity The amount of liquidity in the position,
    /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,
    /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,
    /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,
    /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke
    function positions(bytes32 key)
        external
        view
        returns (
            uint128 _liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    /// @notice Returns data about a specific observation index
    /// @param index The element of the observations array to fetch
    /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time
    /// ago, rather than at a specific index in the array.
    /// @return blockTimestamp The timestamp of the observation,
    /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,
    /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,
    /// Returns initialized whether the observation has been initialized and the values are safe to use
    function observations(uint256 index)
        external
        view
        returns (
            uint32 blockTimestamp,
            int56 tickCumulative,
            uint160 secondsPerLiquidityCumulativeX128,
            bool initialized
        );
}

File 16 of 44 : FullMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0 <0.8.0;

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

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

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

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

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

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

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

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

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

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

File 17 of 44 : TickMath.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
        require(absTick <= uint256(MAX_TICK), 'T');

        uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
        // second inequality must be < because the price can never reach the price at the max tick
        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
        int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);

        tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
    }
}

File 18 of 44 : OracleLibrary.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;

import '@uniswap/v3-core/contracts/libraries/FullMath.sol';
import '@uniswap/v3-core/contracts/libraries/TickMath.sol';
import '@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol';

/// @title Oracle library
/// @notice Provides functions to integrate with V3 pool oracle
library OracleLibrary {
    /// @notice Calculates time-weighted means of tick and liquidity for a given Uniswap V3 pool
    /// @param pool Address of the pool that we want to observe
    /// @param secondsAgo Number of seconds in the past from which to calculate the time-weighted means
    /// @return arithmeticMeanTick The arithmetic mean tick from (block.timestamp - secondsAgo) to block.timestamp
    /// @return harmonicMeanLiquidity The harmonic mean liquidity from (block.timestamp - secondsAgo) to block.timestamp
    function consult(address pool, uint32 secondsAgo)
        internal
        view
        returns (int24 arithmeticMeanTick, uint128 harmonicMeanLiquidity)
    {
        require(secondsAgo != 0, 'BP');

        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = secondsAgo;
        secondsAgos[1] = 0;

        (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s) =
            IUniswapV3Pool(pool).observe(secondsAgos);

        int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
        uint160 secondsPerLiquidityCumulativesDelta =
            secondsPerLiquidityCumulativeX128s[1] - secondsPerLiquidityCumulativeX128s[0];

        arithmeticMeanTick = int24(tickCumulativesDelta / secondsAgo);
        // Always round to negative infinity
        if (tickCumulativesDelta < 0 && (tickCumulativesDelta % secondsAgo != 0)) arithmeticMeanTick--;

        // We are multiplying here instead of shifting to ensure that harmonicMeanLiquidity doesn't overflow uint128
        uint192 secondsAgoX160 = uint192(secondsAgo) * type(uint160).max;
        harmonicMeanLiquidity = uint128(secondsAgoX160 / (uint192(secondsPerLiquidityCumulativesDelta) << 32));
    }

    /// @notice Given a tick and a token amount, calculates the amount of token received in exchange
    /// @param tick Tick value used to calculate the quote
    /// @param baseAmount Amount of token to be converted
    /// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
    /// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
    /// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
    function getQuoteAtTick(
        int24 tick,
        uint128 baseAmount,
        address baseToken,
        address quoteToken
    ) internal pure returns (uint256 quoteAmount) {
        uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);

        // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
        if (sqrtRatioX96 <= type(uint128).max) {
            uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
            quoteAmount = baseToken < quoteToken
                ? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)
                : FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
        } else {
            uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64);
            quoteAmount = baseToken < quoteToken
                ? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128)
                : FullMath.mulDiv(1 << 128, baseAmount, ratioX128);
        }
    }

    /// @notice Given a pool, it returns the number of seconds ago of the oldest stored observation
    /// @param pool Address of Uniswap V3 pool that we want to observe
    /// @return secondsAgo The number of seconds ago of the oldest observation stored for the pool
    function getOldestObservationSecondsAgo(address pool) internal view returns (uint32 secondsAgo) {
        (, , uint16 observationIndex, uint16 observationCardinality, , , ) = IUniswapV3Pool(pool).slot0();
        require(observationCardinality > 0, 'NI');

        (uint32 observationTimestamp, , , bool initialized) =
            IUniswapV3Pool(pool).observations((observationIndex + 1) % observationCardinality);

        // The next index might not be initialized if the cardinality is in the process of increasing
        // In this case the oldest observation is always in index 0
        if (!initialized) {
            (observationTimestamp, , , ) = IUniswapV3Pool(pool).observations(0);
        }

        secondsAgo = uint32(block.timestamp) - observationTimestamp;
    }

    /// @notice Given a pool, it returns the tick value as of the start of the current block
    /// @param pool Address of Uniswap V3 pool
    /// @return The tick that the pool was in at the start of the current block
    function getBlockStartingTickAndLiquidity(address pool) internal view returns (int24, uint128) {
        (, int24 tick, uint16 observationIndex, uint16 observationCardinality, , , ) = IUniswapV3Pool(pool).slot0();

        // 2 observations are needed to reliably calculate the block starting tick
        require(observationCardinality > 1, 'NEO');

        // If the latest observation occurred in the past, then no tick-changing trades have happened in this block
        // therefore the tick in `slot0` is the same as at the beginning of the current block.
        // We don't need to check if this observation is initialized - it is guaranteed to be.
        (uint32 observationTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, ) =
            IUniswapV3Pool(pool).observations(observationIndex);
        if (observationTimestamp != uint32(block.timestamp)) {
            return (tick, IUniswapV3Pool(pool).liquidity());
        }

        uint256 prevIndex = (uint256(observationIndex) + observationCardinality - 1) % observationCardinality;
        (
            uint32 prevObservationTimestamp,
            int56 prevTickCumulative,
            uint160 prevSecondsPerLiquidityCumulativeX128,
            bool prevInitialized
        ) = IUniswapV3Pool(pool).observations(prevIndex);

        require(prevInitialized, 'ONI');

        uint32 delta = observationTimestamp - prevObservationTimestamp;
        tick = int24((tickCumulative - prevTickCumulative) / delta);
        uint128 liquidity =
            uint128(
                (uint192(delta) * type(uint160).max) /
                    (uint192(secondsPerLiquidityCumulativeX128 - prevSecondsPerLiquidityCumulativeX128) << 32)
            );
        return (tick, liquidity);
    }

    /// @notice Information for calculating a weighted arithmetic mean tick
    struct WeightedTickData {
        int24 tick;
        uint128 weight;
    }

    /// @notice Given an array of ticks and weights, calculates the weighted arithmetic mean tick
    /// @param weightedTickData An array of ticks and weights
    /// @return weightedArithmeticMeanTick The weighted arithmetic mean tick
    /// @dev Each entry of `weightedTickData` should represents ticks from pools with the same underlying pool tokens. If they do not,
    /// extreme care must be taken to ensure that ticks are comparable (including decimal differences).
    /// @dev Note that the weighted arithmetic mean tick corresponds to the weighted geometric mean price.
    function getWeightedArithmeticMeanTick(WeightedTickData[] memory weightedTickData)
        internal
        pure
        returns (int24 weightedArithmeticMeanTick)
    {
        // Accumulates the sum of products between each tick and its weight
        int256 numerator;

        // Accumulates the sum of the weights
        uint256 denominator;

        // Products fit in 152 bits, so it would take an array of length ~2**104 to overflow this logic
        for (uint256 i; i < weightedTickData.length; i++) {
            numerator += weightedTickData[i].tick * int256(weightedTickData[i].weight);
            denominator += weightedTickData[i].weight;
        }

        weightedArithmeticMeanTick = int24(numerator / int256(denominator));
        // Always round to negative infinity
        if (numerator < 0 && (numerator % int256(denominator) != 0)) weightedArithmeticMeanTick--;
    }

    /// @notice Returns the "synthetic" tick which represents the price of the first entry in `tokens` in terms of the last
    /// @dev Useful for calculating relative prices along routes.
    /// @dev There must be one tick for each pairwise set of tokens.
    /// @param tokens The token contract addresses
    /// @param ticks The ticks, representing the price of each token pair in `tokens`
    /// @return syntheticTick The synthetic tick, representing the relative price of the outermost tokens in `tokens`
    function getChainedPrice(address[] memory tokens, int24[] memory ticks)
        internal
        pure
        returns (int256 syntheticTick)
    {
        require(tokens.length - 1 == ticks.length, 'DL');
        for (uint256 i = 1; i <= ticks.length; i++) {
            // check the tokens for address sort order, then accumulate the
            // ticks into the running synthetic tick, ensuring that intermediate tokens "cancel out"
            tokens[i - 1] < tokens[i] ? syntheticTick += ticks[i - 1] : syntheticTick -= ticks[i - 1];
        }
    }
}

File 19 of 44 : 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
    }

    /**
     * @notice Stores a Farmer's Stalk and Seeds balances.
     * @param stalk Balance of the Farmer's Stalk.
     * @param seeds Balance of the Farmer's Seeds.
     */
    struct Silo {
        uint256 stalk;
        uint256 seeds;
    }

    /**
     * @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;
        AssetSilo bean;
        AssetSilo lp;
        Silo s;
        uint32 deprecated_votedUntil; // ─────┐ 4
        uint32 lastUpdate; //                 β”‚ 4
        uint32 lastSop; //                    β”‚ 4
        uint32 lastRain; //                   β”‚ 4
        uint32 deprecated_lastSIs; //         β”‚ 4
        uint32 deprecated_proposedUntil; // β”€β”€β”˜ 4
        SeasonOfPlenty deprecated_sop;
        uint256 roots;
        uint256 deprecated_wrappedBeans;
        mapping(address => mapping(uint32 => Deposit)) deposits;
        mapping(address => mapping(uint32 => uint256)) withdrawals;
        SeasonOfPlenty sop;
        mapping(address => mapping(address => uint256)) depositAllowances;
        mapping(address => mapping(IERC20 => uint256)) tokenAllowances;
        uint256 depositPermitNonces;
        uint256 tokenPermitNonces;
    }
}

/**
 * @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
        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.
     * 
     * FIXME: pauseOrUnpause takes up an entire slot
     */
    struct Bip {
        address proposer; // ───┐ 20
        uint32 start; //        β”‚ 4
        uint32 period; //       β”‚ 4
        bool executed; // β”€β”€β”€β”€β”€β”€β”˜ 1
        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.
     */
    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.
     */
    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 withdrawn The total amount of this Token currently Withdrawn From the Silo.
     * @dev {Storage.State} contains a mapping from Token address => AssetSilo.
     * 
     * 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 {
        uint256 deposited;
        uint256 withdrawn;
    }

    /**
     * @notice System-level Silo state variables.
     * @param stalk The total amount of active Stalk (including Earned Stalk, excluding Grown Stalk).
     * @param seeds The total amount of active Seeds (excluding Earned Seeds).
     * @param roots The total amount of Roots.
     */
    struct Silo {
        uint256 stalk;
        uint256 seeds;
        uint256 roots;
    }

    /**
     * @notice System-level 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 The timestamp of the start of the current Season.
     * @dev Currently refers to the time weighted average deltaB calculated from the BEAN:3CRV pool.
     */
    struct Oracle {
        bool initialized; // ────┐ 1
        uint32 startSeason; // β”€β”€β”˜ 4
        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 FIXME
     * @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 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
        uint8 withdrawSeasons; // β”‚ 1
        uint32 lastSopSeason; //  β”‚ 4
        uint32 rainStart; //      β”‚ 4
        bool raining; //          β”‚ 1
        bool fertilizing; //      β”‚ 1
        uint32 sunriseBlock; //   β”‚ 4
        bool abovePeg; // β”€β”€β”€β”€β”€β”€β”€β”€β”˜ 1
        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
        uint32 lastSowTime; //   β”‚ 4
        uint32 thisSowTime; //   β”‚ 4
        uint32 t; // β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ 4
    }

    /**
     * @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 {
        bytes4 selector; // ───┐ 4
        uint32 seeds; //       β”‚ 4
        uint32 stalk; // β”€β”€β”€β”€β”€β”€β”˜ 4
    }

    /**
     * @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.Oracle
 * @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 - 3 slots that used to store state variables which have been depreciated through various updates. Storage slots can be left alone or reused.
 * @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 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.
 */
struct AppStorage {
    uint8 deprecated_index;
    int8[32] cases; 
    bool paused; // ────────┐ 1
    uint128 pausedAt; // β”€β”€β”€β”˜ 16
    Storage.Season season;
    Storage.Contracts c;
    Storage.Field f;
    Storage.Governance g;
    Storage.Oracle 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
    mapping (uint32 => Storage.Fundraiser) fundraisers;
    uint32 fundraiserIndex;
    mapping (address => bool) deprecated_isBudget;
    mapping(uint256 => bytes32) podListings;
    mapping(bytes32 => uint256) podOrders;
    mapping(address => Storage.AssetSilo) siloBalances;
    mapping(address => Storage.SiloSettings) ss;
    uint256[3] deprecated2;

    // New Sops
    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; // ───┐ 16
    uint128 fLast; // β”€β”€β”€β”€β”˜ 16
    uint128 bpf;
    uint256 recapitalized;
    uint256 isFarm;
    address ownerCandidate;
}

File 20 of 44 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;
import "./AppStorage.sol";

/**
 * @author Beanstalk Farms
 * @title Variation of Oepn Zeppelins reentrant guard to include Silo Update
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts%2Fsecurity%2FReentrancyGuard.sol
**/
abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    AppStorage internal s;
    
    modifier nonReentrant() {
        require(s.reentrantStatus != _ENTERED, "ReentrancyGuard: reentrant call");
        s.reentrantStatus = _ENTERED;
        _;
        s.reentrantStatus = _NOT_ENTERED;
    }
}

File 21 of 44 : Oracle.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "contracts/libraries/Oracle/LibCurveOracle.sol";
import "contracts/beanstalk/ReentrancyGuard.sol";

/**
 * @title Oracle
 * @author Publius, Chaikitty
 * @notice Tracks the Delta B in available pools.
 */
contract Oracle is ReentrancyGuard {
    
    //////////////////// ORACLE GETTERS ////////////////////

    /**
     * @notice Returns the current Delta B in the Curve liquidity pool.
     */
    function totalDeltaB() external view returns (int256 deltaB) {
        deltaB = LibCurveOracle.check();
    }

    /**
     * @notice Returns the current Delta B for the requested pool.
     */
    function poolDeltaB(address pool) external view returns (int256) {
        if (pool == C.CURVE_BEAN_METAPOOL) return LibCurveOracle.check();
        revert("Oracle: Pool not supported");
    }

    //////////////////// ORACLE INTERNAL ////////////////////

    function stepOracle() internal returns (int256 deltaB, uint256[2] memory balances) {
        (deltaB, balances) = LibCurveOracle.capture();
    }
}

File 22 of 44 : Sun.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;
pragma experimental ABIEncoderV2;

import "contracts/libraries/Decimal.sol";
import "contracts/libraries/LibSafeMath32.sol";
import "contracts/libraries/LibFertilizer.sol";
import "contracts/libraries/LibPRBMath.sol";
import "contracts/C.sol";
import "./Oracle.sol";

/**
 * @title Sun
 * @author Publius
 * @notice Sun controls the minting of new Beans to Fertilizer, the Field, and the Silo.
 */
contract Sun is Oracle {
    using SafeMath for uint256;
    using LibPRBMath for uint256;
    using LibSafeMath32 for uint32;
    using Decimal for Decimal.D256;

    /// @dev When Fertilizer is Active, it receives 1/3 of new Bean mints.
    uint256 private constant FERTILIZER_DENOMINATOR = 3;

    /// @dev After Fertilizer, Harvestable Pods receive 1/2 of new Bean mints. 
    uint256 private constant HARVEST_DENOMINATOR = 2;

    /// @dev When the Pod Rate is high, issue less Soil.
    uint256 private constant SOIL_COEFFICIENT_HIGH = 0.5e18;
    
    /// @dev When the Pod Rate is low, issue more Soil.
    uint256 private constant SOIL_COEFFICIENT_LOW = 1.5e18;

    /**
     * @notice Emitted during Sunrise when Beans are distributed to the Field, the Silo, and Fertilizer.
     * @param season The Season in which Beans were distributed.
     * @param toField The number of Beans distributed to the Field.
     * @param toSilo The number of Beans distributed to the Silo.
     * @param toFertilizer The number of Beans distributed to Fertilizer.
     */
    event Reward(
        uint32 indexed season,
        uint256 toField,
        uint256 toSilo,
        uint256 toFertilizer
    );

    /**
     * @notice Emitted during Sunrise when Beanstalk adjusts the amount of available Soil.
     * @param season The Season in which Soil was adjusted.
     * @param soil The new amount of Soil available.
     */
    event Soil(
        uint32 indexed season,
        uint256 soil
    );

    //////////////////// SUN INTERNAL ////////////////////
    
    /**
     * @param deltaB Pre-calculated deltaB from {Oracle.stepOracle}.
     * @param caseId Pre-calculated Weather case from {Weather.stepWeather}.
     */
    function stepSun(int256 deltaB, uint256 caseId) internal {
        // Above peg
        if (deltaB > 0) {
            uint256 newHarvestable = rewardBeans(uint256(deltaB));
            setSoilAbovePeg(newHarvestable, caseId);
            s.season.abovePeg = true;
        } 

        // Below peg
        else {
            setSoil(uint256(-deltaB));
            s.season.abovePeg = false;
        }
    }

    //////////////////// REWARD BEANS ////////////////////

    /**
     * @dev Mints and distributes Beans to Fertilizer, the Field, and the Silo.
     */
    function rewardBeans(uint256 newSupply) internal returns (uint256 newHarvestable) {
        uint256 newFertilized;
        
        C.bean().mint(address(this), newSupply);

        // Distribute first to Fertilizer if some Fertilizer are active
        if (s.season.fertilizing) {
            newFertilized = rewardToFertilizer(newSupply);
            newSupply = newSupply.sub(newFertilized);
        }

        // Distribute next to the Field if some Pods are still outstanding
        if (s.f.harvestable < s.f.pods) {
            newHarvestable = rewardToHarvestable(newSupply);
            newSupply = newSupply.sub(newHarvestable);
        }

        // Distribute remainder to the Silo
        rewardToSilo(newSupply);

        emit Reward(s.season.current, newHarvestable, newSupply, newFertilized);
    }

    /**
     * @dev Distributes Beans to Fertilizer.
     */
    function rewardToFertilizer(uint256 amount)
        internal
        returns (uint256 newFertilized)
    {
        // 1/3 of new Beans being minted
        uint256 maxNewFertilized = amount.div(FERTILIZER_DENOMINATOR);

        // Get the new Beans per Fertilizer and the total new Beans per Fertilizer
        uint256 newBpf = maxNewFertilized.div(s.activeFertilizer);
        uint256 oldTotalBpf = s.bpf;
        uint256 newTotalBpf = oldTotalBpf.add(newBpf);

        // Get the end Beans per Fertilizer of the first Fertilizer to run out.
        uint256 firstEndBpf = s.fFirst;

        // If the next fertilizer is going to run out, then step BPF according
        while(newTotalBpf >= firstEndBpf) {
            // Calculate BPF and new Fertilized when the next Fertilizer ID ends
            newBpf = firstEndBpf.sub(oldTotalBpf);
            newFertilized = newFertilized.add(newBpf.mul(s.activeFertilizer));

            // If there is no more fertilizer, end
            if (!LibFertilizer.pop()) {
                s.bpf = uint128(firstEndBpf);
                s.fertilizedIndex = s.fertilizedIndex.add(newFertilized);
                require(s.fertilizedIndex == s.unfertilizedIndex, "Paid != owed");
                return newFertilized;
            }

            // Calculate new Beans per Fertilizer values
            newBpf = maxNewFertilized.sub(newFertilized).div(s.activeFertilizer);
            oldTotalBpf = firstEndBpf;
            newTotalBpf = oldTotalBpf.add(newBpf);
            firstEndBpf = s.fFirst;
        }

        // Distribute the rest of the Fertilized Beans
        s.bpf = uint128(newTotalBpf); // SafeCast unnecessary here.
        newFertilized = newFertilized.add(newBpf.mul(s.activeFertilizer));
        s.fertilizedIndex = s.fertilizedIndex.add(newFertilized);
    }

    /**
     * @dev Distributes Beans to the Field. The next `amount` Pods in the Pod Line
     * become Harvestable.
     */
    function rewardToHarvestable(uint256 amount)
        internal    
        returns (uint256 newHarvestable)
    {
        uint256 notHarvestable = s.f.pods - s.f.harvestable; // Note: SafeMath is redundant here.
        newHarvestable = amount.div(HARVEST_DENOMINATOR);
        newHarvestable = newHarvestable > notHarvestable
            ? notHarvestable
            : newHarvestable;
        s.f.harvestable = s.f.harvestable.add(newHarvestable);
    }

    /**
     * @dev Distribute Beans to the Silo. Stalk & Earned Beans are created here;
     * Farmers can claim them through {SiloFacet.plant}.
     */
    function rewardToSilo(uint256 amount) internal {
        s.s.stalk = s.s.stalk.add(amount.mul(C.STALK_PER_BEAN));
        s.earnedBeans = s.earnedBeans.add(amount);
        s.siloBalances[C.BEAN].deposited = s
            .siloBalances[C.BEAN]
            .deposited
            .add(amount);
    }

    //////////////////// SET SOIL ////////////////////

    /**
     * @param newHarvestable The number of Beans that were minted to the Field.
     * @param caseId The current Weather Case.
     * @dev When above peg, Beanstalk wants to gauge demand for Soil. Here it
     * issues the amount of Soil that would result in the same number of Pods
     * as became Harvestable during the last Season.
     * 
     * When the Pod Rate is high, Beanstalk issues less Soil.
     * When the Pod Rate is low, Beanstalk issues more Soil.
     */
    function setSoilAbovePeg(uint256 newHarvestable, uint256 caseId) internal {
        uint256 newSoil = newHarvestable.mul(100).div(100 + s.w.t);
        if (caseId >= 24) {
            newSoil = newSoil.mul(SOIL_COEFFICIENT_HIGH).div(C.PRECISION); // high podrate
        } else if (caseId < 8) {
            newSoil = newSoil.mul(SOIL_COEFFICIENT_LOW).div(C.PRECISION); // low podrate
        }
        setSoil(newSoil);
    }

    
    function setSoil(uint256 amount) internal {
        s.f.soil = uint128(amount);
        emit Soil(s.season.current, amount);
    }
}

File 23 of 44 : Weather.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "contracts/libraries/Decimal.sol";
import "contracts/libraries/Curve/LibBeanMetaCurve.sol";
import "./Sun.sol";

library DecimalExtended {
    uint256 private constant PERCENT_BASE = 1e18;

    function toDecimal(uint256 a) internal pure returns (Decimal.D256 memory) {
        return Decimal.D256({ value: a });
    }
}

/**
 * @title Weather
 * @author Publius
 * @notice Weather controls the Temperature on the Farm.
 */
contract Weather is Sun {
    using SafeMath for uint256;
    using DecimalExtended for uint256;
    using LibSafeMath32 for uint32;
    using Decimal for Decimal.D256;

    /// @dev If all Soil is Sown faster than this, Beanstalk considers demand for Soil to be increasing.
    uint256 private constant SOW_TIME_DEMAND_INCR = 600; // seconds

    uint32 private constant SOW_TIME_STEADY = 60; // seconds

    uint256 private constant POD_RATE_LOWER_BOUND = 0.05e18; // 5%
    uint256 private constant POD_RATE_OPTIMAL = 0.15e18; // 15%
    uint256 private constant POD_RATE_UPPER_BOUND = 0.25e18; // 25%

    uint256 private constant DELTA_POD_DEMAND_LOWER_BOUND = 0.95e18; // 95%
    uint256 private constant DELTA_POD_DEMAND_UPPER_BOUND = 1.05e18; // 105%
    
    /**
     * @notice Emitted when the Temperature (fka "Weather") changes.
     * @param season The current Season
     * @param caseId The Weather case, which determines how much the Temperature is adjusted.
     * @param change The change in Temperature as a delta from the previous value
     * @dev The name {WeatherChange} is kept for backwards compatibility, 
     * however the state variable included as `change` is now called Temperature.
     * 
     * `change` is emitted as a delta for gas efficiency.
     */
    event WeatherChange(
        uint256 indexed season,
        uint256 caseId,
        int8 change
    );

    /**
     * @notice Emitted when Beans are minted during the Season of Plenty.
     * @param season The Season in which Beans were minted for distribution.
     * @param amount The amount of 3CRV which was received for swapping Beans.
     * @param toField The amount of Beans which were distributed to remaining Pods in the Field.
     */
    event SeasonOfPlenty(
        uint256 indexed season,
        uint256 amount,
        uint256 toField
    );


    //////////////////// WEATHER GETTERS ////////////////////

    /**
     * @notice Returns the current Weather struct. See {AppStorage:Storage.Weather}.
     */
    function weather() public view returns (Storage.Weather memory) {
        return s.w;
    }

    /**
     * @notice Returns the current Rain struct. See {AppStorage:Storage.Rain}.
     */
    function rain() public view returns (Storage.Rain memory) {
        return s.r;
    }

    /**
     * @notice Returns the Plenty per Root for `season`.
     */
    function plentyPerRoot(uint32 season) external view returns (uint256) {
        return s.sops[season];
    }

    //////////////////// WEATHER INTERNAL ////////////////////

    /**
     * @param deltaB Pre-calculated deltaB from {Oracle.stepOracle}.
     * @dev A detailed explanation of the Weather mechanism can be found in the
     * Beanstalk whitepaper. An explanation of state variables can be found in {AppStorage}.
     */
    function stepWeather(int256 deltaB) internal returns (uint256 caseId) {
        uint256 beanSupply = C.bean().totalSupply();

        // Prevent infinite pod rate
        if (beanSupply == 0) {
            s.w.t = 1;
            return 8; // Reasonably low
        }

        // Calculate Pod Rate
        Decimal.D256 memory podRate = Decimal.ratio(
            s.f.pods.sub(s.f.harvestable), // same as totalUnharvestable()
            beanSupply
        );

        // Calculate Delta Soil Demand
        uint256 dsoil = s.f.beanSown;
        s.f.beanSown = 0;
    
        Decimal.D256 memory deltaPodDemand;

        // `s.w.thisSowTime` is set to the number of seconds in it took for 
        // Soil to sell out during the current Season. If Soil didn't sell out,
        // it remains `type(uint32).max`.
        if (s.w.thisSowTime < type(uint32).max) {
            if (
                s.w.lastSowTime == type(uint32).max || // Didn't Sow all last Season
                s.w.thisSowTime < SOW_TIME_DEMAND_INCR || // Sow'd all instantly this Season
                (s.w.lastSowTime > SOW_TIME_STEADY &&
                    s.w.thisSowTime < s.w.lastSowTime.sub(SOW_TIME_STEADY)) // Sow'd all faster
            ) {
                deltaPodDemand = Decimal.from(1e18);
            } else if (
                s.w.thisSowTime <= s.w.lastSowTime.add(SOW_TIME_STEADY)
            ) {
                // Sow'd all in same time
                deltaPodDemand = Decimal.one();
            } else { 
                deltaPodDemand = Decimal.zero();
            }

            s.w.lastSowTime = s.w.thisSowTime;  // Overwrite last Season
            s.w.thisSowTime = type(uint32).max; // Reset for next Season
        } 

        // Soil didn't sell out
        else {
            uint256 lastDSoil = s.w.lastDSoil;

            if (dsoil == 0) {
                deltaPodDemand = Decimal.zero(); // If no one sow'd
            } else if (lastDSoil == 0) {
                deltaPodDemand = Decimal.from(1e18); // If no one sow'd last Season
            } else { 
                deltaPodDemand = Decimal.ratio(dsoil, lastDSoil);
            }

            if (s.w.lastSowTime != type(uint32).max) {
                s.w.lastSowTime = type(uint32).max;
            }
        }
        
        // Calculate Weather Case
        caseId = 0;

        // Evaluate Pod Rate
        if (podRate.greaterThanOrEqualTo(POD_RATE_UPPER_BOUND.toDecimal())) {
            caseId = 24;
        } else if (podRate.greaterThanOrEqualTo(POD_RATE_OPTIMAL.toDecimal())) {
            caseId = 16;
        } else if (podRate.greaterThanOrEqualTo(POD_RATE_LOWER_BOUND.toDecimal())) {
            caseId = 8;
        }

        // Evaluate Price
        if (
            deltaB > 0 ||
            (deltaB == 0 && podRate.lessThanOrEqualTo(POD_RATE_OPTIMAL.toDecimal()))
        ) {
            caseId += 4;
        }

        // Evaluate Delta Soil Demand
        if (deltaPodDemand.greaterThanOrEqualTo(DELTA_POD_DEMAND_UPPER_BOUND.toDecimal())) {
            caseId += 2;
        } else if (deltaPodDemand.greaterThanOrEqualTo(DELTA_POD_DEMAND_LOWER_BOUND.toDecimal())) {
            caseId += 1;
        }

        s.w.lastDSoil = uint128(dsoil); // SafeCast not necessary as `s.f.beanSown` is uint128.
        
        changeWeather(caseId);
        handleRain(caseId);
    }

    /**
     * @dev Changes the current Temperature `s.w.t` based on the Weather Case.
     */
    function changeWeather(uint256 caseId) private {
        int8 change = s.cases[caseId];
        uint32 t = s.w.t;

        if (change < 0) {
            if (t <= (uint32(-change))) {
                // if (change < 0 && t <= uint32(-change)),
                // then 0 <= t <= type(int8).max because change is an int8.
                // Thus, downcasting t to an int8 will not cause overflow.
                change = 1 - int8(t);
                s.w.t = 1;
            } else {
                s.w.t = t - (uint32(-change));
            }
        } else {
            s.w.t = t + (uint32(change));
        }

        emit WeatherChange(s.season.current, caseId, change);
    }

    /**
     * @dev Update Rain state based on the current state and Weather Case.
     */
    function handleRain(uint256 caseId) internal {
        if (caseId < 4 || caseId > 7) {
            if (s.season.raining) {
                s.season.raining = false;
            }
            return;
        } else if (!s.season.raining) {
            s.season.raining = true;
            // Set the plenty per root equal to previous rain start.
            s.sops[s.season.current] = s.sops[s.season.rainStart];
            s.season.rainStart = s.season.current;
            s.r.pods = s.f.pods;
            s.r.roots = s.s.roots;
        } else if (
            s.season.current >= s.season.rainStart.add(s.season.withdrawSeasons - 1)
        ) {
            if (s.r.roots > 0) {
                sop();
            }
        }
    }

    /**
     * @dev Sell Beans on the Curve pool for 3CRV.
     */
    function sop() private {
        int256 newBeans = LibBeanMetaCurve.getDeltaB();
        if (newBeans <= 0) return;

        uint256 sopBeans = uint256(newBeans);
        uint256 newHarvestable;

        // Pay off remaining Pods if any exist.
        if (s.f.harvestable < s.r.pods) {
            newHarvestable = s.r.pods - s.f.harvestable;
            s.f.harvestable = s.f.harvestable.add(newHarvestable);
            C.bean().mint(address(this), newHarvestable.add(sopBeans));
        } else {
            C.bean().mint(address(this), sopBeans);
        }

        // Swap Beans for 3CRV.
        uint256 amountOut = C.curveMetapool().exchange(0, 1, sopBeans, 0);

        rewardSop(amountOut);
        emit SeasonOfPlenty(s.season.current, amountOut, newHarvestable);
    }

    /**
     * @dev Allocate 3CRV during a Season of Plenty.
     */
    function rewardSop(uint256 amount) private {
        s.sops[s.season.rainStart] = s.sops[s.season.lastSop].add(
            amount.mul(C.SOP_PRECISION).div(s.r.roots)
        );
        s.season.lastSop = s.season.rainStart;
        s.season.lastSopSeason = s.season.current;
    }
}

File 24 of 44 : 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;

    /// @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 WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address internal constant UNIV3_ETH_USDC_POOL = 0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8;

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

    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;
    }

    function unripeLPPool1() internal pure returns (address) {
        return UNRIPE_CURVE_BEAN_METAPOOL;
    }

    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 25 of 44 : 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;
}

File 26 of 44 : IBlockBasefee.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;

interface IBlockBasefee {
    // Returns the base fee of this block in wei
    function block_basefee() external view returns (uint256);
}

File 27 of 44 : 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 28 of 44 : 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 29 of 44 : 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 30 of 44 : IProxyAdmin.sol
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity =0.7.6;
interface IProxyAdmin {
    function upgrade(address proxy, address implementation) external;
}

File 31 of 44 : LibBeanMetaCurve.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {LibMetaCurve, IMeta3Curve} from "./LibMetaCurve.sol";
import {LibCurve} from "./LibCurve.sol";
import "contracts/C.sol";

/**
 * @title LibBeanMetaCurve
 * @author Publius
 * @notice Calculates BDV and deltaB for the BEAN:3CRV Metapool.
 */
library LibBeanMetaCurve {
    using SafeMath for uint256;

    uint256 private constant RATE_MULTIPLIER = 1e12; // Bean has 6 Decimals => 1e(18 - delta decimals)
    uint256 private constant PRECISION = 1e18;
    uint256 private constant i = 0;
    uint256 private constant j = 1;

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

    /**
     * @param amount An amount of the BEAN:3CRV LP token.
     * @dev Calculates the current BDV of BEAN given the balances in the BEAN:3CRV
     * Metapool. NOTE: assumes that `balances[0]` is BEAN.
     */
    function bdv(uint256 amount) internal view returns (uint256) {
        // By using previous balances and the virtual price, we protect against flash loan
        uint256[2] memory balances = IMeta3Curve(C.CURVE_BEAN_METAPOOL).get_previous_balances();
        uint256 virtualPrice = C.curveMetapool().get_virtual_price();
        uint256[2] memory xp = LibMetaCurve.getXP(balances, RATE_MULTIPLIER);

        uint256 a = C.curveMetapool().A_precise();
        uint256 D = LibCurve.getD(xp, a);
        uint256 price = LibCurve.getPrice(xp, a, D, RATE_MULTIPLIER);
        uint256 totalSupply = (D * PRECISION) / virtualPrice;
        uint256 beanValue = balances[0].mul(amount).div(totalSupply);
        uint256 curveValue = xp[1].mul(amount).div(totalSupply).div(price);
        
        return beanValue.add(curveValue);
    }

    function getDeltaB() internal view returns (int256 deltaB) {
        uint256[2] memory balances = C.curveMetapool().get_balances();
        uint256 d = getDFroms(balances);
        deltaB = getDeltaBWithD(balances[0], d);
    }
    
    function getDeltaBWithD(uint256 balance, uint256 D)
        internal
        pure
        returns (int256 deltaB)
    {
        uint256 pegBeans = D / 2 / RATE_MULTIPLIER;
        deltaB = int256(pegBeans) - int256(balance);
    }

    //////////////////// CURVE HELPERS ////////////////////

    /**
     * @dev D = the number of LP tokens times the virtual price.
     * LP supply = D / virtual price. D increases as pool accumulates fees.
     * D = number of stable tokens in the pool when the pool is balanced. 
     * 
     * Rate multiplier for BEAN is 1e12.
     * Rate multiplier for 3CRV is virtual price.
     */
    function getDFroms(uint256[2] memory balances)
        internal
        view
        returns (uint256)
    {
        return LibMetaCurve.getDFroms(
            C.CURVE_BEAN_METAPOOL,
            balances,
            RATE_MULTIPLIER
        );
    }

    /**
     * @dev `xp = balances * RATE_MULTIPLIER`
     */
    function getXP(uint256[2] memory balances)
        internal
        view
        returns (uint256[2] memory xp)
    {
        xp = LibMetaCurve.getXP(balances, RATE_MULTIPLIER);
    }

    /**
     * @dev Convert from `balance` -> `xp0`, which is scaled up by `RATE_MULTIPLIER`.
     */
    function getXP0(uint256 balance)
        internal
        pure
        returns (uint256 xp0)
    {
        xp0 = balance.mul(RATE_MULTIPLIER);
    }

    /**
     * @dev Convert from `xp0` -> `balance`, which is scaled down by `RATE_MULTIPLIER`.
     */
    function getX0(uint256 xp0)
        internal
        pure
        returns (uint256 balance0)
    {
        balance0 = xp0.div(RATE_MULTIPLIER);
    }
}

File 32 of 44 : LibCurve.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

/**
 * @title LibCurve
 * @author Publius
 * @notice Low-level Curve swap math for a 2-token StableSwap pool.
 */
library LibCurve {
    using SafeMath for uint256;

    uint256 private constant A_PRECISION = 100;
    uint256 private constant N_COINS = 2;
    uint256 private constant PRECISION = 1e18;
    uint256 private constant i = 0;
    uint256 private constant j = 1;

    /**
     * @dev Find the change in token `j` given a change in token `i`.
     */
    function getPrice(
        uint256[2] memory xp,
        uint256 a,
        uint256 D,
        uint256 padding
    ) internal pure returns (uint256) {
        uint256 x = xp[i] + padding;
        uint256 y = getY(x, xp, a, D);
        uint256 dy = xp[j] - y - 1;
        return dy;
    }

    function getPrice(
        uint256[2] memory xp,
        uint256[2] memory rates,
        uint256 a,
        uint256 D
    ) internal pure returns (uint256) {
        uint256 x = xp[i] + ((1 * rates[i]) / PRECISION);
        uint256 y = getY(x, xp, a, D);
        uint256 dy = xp[j] - y - 1;
        return dy / 1e6;
    }

    function getY(
        uint256 x,
        uint256[2] memory xp,
        uint256 a,
        uint256 D
    ) internal pure returns (uint256 y) {
        // Solution is taken from pool contract: 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49
        uint256 S_ = 0;
        uint256 _x = 0;
        uint256 y_prev = 0;
        uint256 c = D;
        uint256 Ann = a * N_COINS;

        for (uint256 _i; _i < N_COINS; ++_i) {
            if (_i == i) _x = x;
            else if (_i != j) _x = xp[_i];
            else continue;
            S_ += _x;
            c = (c * D) / (_x * N_COINS);
        }

        c = (c * D * A_PRECISION) / (Ann * N_COINS);
        uint256 b = S_ + (D * A_PRECISION) / Ann; // - D
        y = D;

        for (uint256 _i; _i < 255; ++_i) {
            y_prev = y;
            y = (y * y + c) / (2 * y + b - D);
            if (y > y_prev && y - y_prev <= 1) return y;
            else if (y_prev - y <= 1) return y;
        }
        require(false, "Price: Convergence false");
    }

    function getD(uint256[2] memory xp, uint256 a)
        internal
        pure
        returns (uint256 D)
    {
        // Solution is taken from pool contract: 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49
        uint256 S;
        uint256 Dprev;
        for (uint256 _i; _i < xp.length; ++_i) {
            S += xp[_i];
        }
        if (S == 0) return 0;

        D = S;
        uint256 Ann = a * N_COINS;
        for (uint256 _i; _i < 256; ++_i) {
            uint256 D_P = D;
            for (uint256 _j; _j < xp.length; ++_j) {
                D_P = (D_P * D) / (xp[_j] * N_COINS);
            }
            Dprev = D;
            D =
                (((Ann * S) / A_PRECISION + D_P * N_COINS) * D) /
                (((Ann - A_PRECISION) * D) / A_PRECISION + (N_COINS + 1) * D_P);
            if (D > Dprev && D - Dprev <= 1) return D;
            else if (Dprev - D <= 1) return D;
        }
        require(false, "Price: Convergence false");
        return 0;
    }

    function getYD(
        uint256 a,
        uint256 i_,
        uint256[2] memory xp,
        uint256 D
    ) internal pure returns (uint256 y) {
        // Solution is taken from pool contract: 0xc9C32cd16Bf7eFB85Ff14e0c8603cc90F6F2eE49
        uint256 S_ = 0;
        uint256 _x = 0;
        uint256 y_prev = 0;
        uint256 c = D;
        uint256 Ann = a * N_COINS;

        for (uint256 _i; _i < N_COINS; ++_i) {
            if (_i != i_) _x = xp[_i];
            else continue;
            S_ += _x;
            c = (c * D) / (_x * N_COINS);
        }

        c = (c * D * A_PRECISION) / (Ann * N_COINS);
        uint256 b = S_ + (D * A_PRECISION) / Ann; // - D
        y = D;

        for (uint256 _i; _i < 255; ++_i) {
            y_prev = y;
            y = (y * y + c) / (2 * y + b - D);
            if (y > y_prev && y - y_prev <= 1) return y;
            else if (y_prev - y <= 1) return y;
        }
        require(false, "Price: Convergence false");
    }

    /**
     * @dev Return the `xp` array for two tokens. Adjusts `balances[0]` by `padding`
     * and `balances[1]` by `rate / PRECISION`.
     * 
     * This is provided as a gas optimization when `rates[0] * PRECISION` has been
     * pre-computed.
     */
    function getXP(
        uint256[2] memory balances,
        uint256 padding,
        uint256 rate
    ) internal pure returns (uint256[2] memory xp) {
        xp[0] = balances[0].mul(padding);
        xp[1] = balances[1].mul(rate).div(PRECISION);
    }

    /**
     * @dev Return the `xp` array for two tokens. Adjusts `balances[0]` by `rates[0]`
     * and `balances[1]` by `rates[1] / PRECISION`.
     */
    function getXP(
        uint256[2] memory balances,
        uint256[2] memory rates
    ) internal pure returns (uint256[2] memory xp) {
        xp[0] = balances[0].mul(rates[0]).div(PRECISION);
        xp[1] = balances[1].mul(rates[1]).div(PRECISION);
    }
}

File 33 of 44 : LibMetaCurve.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

/**
 * @dev Curve Metapool extended interface.
 */
interface IMeta3Curve {
    function A_precise() external view returns (uint256);
    function get_previous_balances() external view returns (uint256[2] memory);
    function get_virtual_price() external view returns (uint256);
}

/**
 * @title LibMetaCurve
 * @author Publius
 * @notice Wraps {LibCurve} with metadata about Curve Metapools, including the
 * `A` parameter and virtual price.
 */
library LibMetaCurve {
    using SafeMath for uint256;
    
    /**
     * @dev Used in {LibBeanMetaCurve}.
     */
    function getXP(
        uint256[2] memory balances,
        uint256 padding
    ) internal view returns (uint256[2] memory) {
        return LibCurve.getXP(
            balances,
            padding,
            C.curve3Pool().get_virtual_price()
        );
    }

    /**
     * @dev Used in {LibBeanMetaCurve}.
     */
    function getDFroms(
        address pool,
        uint256[2] memory balances,
        uint256 padding
    ) internal view returns (uint256) {
        return LibCurve.getD(
            getXP(balances, padding),
            IMeta3Curve(pool).A_precise()
        );
    }
}

File 34 of 44 : 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 35 of 44 : 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 36 of 44 : LibFertilizer.sol
/*
 SPDX-License-Identifier: MIT
*/

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "./LibAppStorage.sol";
import "./LibSafeMath128.sol";
import "../C.sol";
import "./LibUnripe.sol";

/**
 * @author Publius
 * @title Fertilizer
 **/

library LibFertilizer {
    using SafeMath for uint256;
    using LibSafeMath128 for uint128;

    event SetFertilizer(uint128 id, uint128 bpf);

    // 6 - 3
    uint128 private constant PADDING = 1e3;
    uint128 private constant DECIMALS = 1e6;
    uint128 private constant REPLANT_SEASON = 6074;
    uint128 private constant RESTART_HUMIDITY = 2500;
    uint128 private constant END_DECREASE_SEASON = REPLANT_SEASON + 461;

    function addFertilizer(
        uint128 season,
        uint128 amount,
        uint256 minLP
    ) internal returns (uint128 id) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 _amount = uint256(amount);
        // Calculate Beans Per Fertilizer and add to total owed
        uint128 bpf = getBpf(season);
        s.unfertilizedIndex = s.unfertilizedIndex.add(
            _amount.mul(uint128(bpf))
        );
        // Get id
        id = s.bpf.add(bpf);
        // Update Total and Season supply
        s.fertilizer[id] = s.fertilizer[id].add(amount);
        s.activeFertilizer = s.activeFertilizer.add(_amount);
        // Add underlying to Unripe Beans and Unripe LP
        addUnderlying(_amount.mul(DECIMALS), minLP);
        // If not first time adding Fertilizer with this id, return
        if (s.fertilizer[id] > amount) return id;
        // If first time, log end Beans Per Fertilizer and add to Season queue.
        LibFertilizer.push(id);
        emit SetFertilizer(id, bpf);
    }

    function getBpf(uint128 id) internal pure returns (uint128 bpf) {
        bpf = getHumidity(id).add(1000).mul(PADDING);
    }

    function getHumidity(uint128 id) internal pure returns (uint128 humidity) {
        if (id == 0) return 5000;
        if (id >= END_DECREASE_SEASON) return 200;
        uint128 humidityDecrease = id.sub(REPLANT_SEASON).mul(5);
        humidity = RESTART_HUMIDITY.sub(humidityDecrease);
    }

    function addUnderlying(uint256 amount, uint256 minAmountOut) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        // Calculate how many new Deposited Beans will be minted
        uint256 percentToFill = amount.mul(C.precision()).div(
            remainingRecapitalization()
        );
        uint256 newDepositedBeans;
        if (C.unripeBean().totalSupply() > s.u[C.UNRIPE_BEAN].balanceOfUnderlying) {
            newDepositedBeans = (C.unripeBean().totalSupply()).sub(
                s.u[C.UNRIPE_BEAN].balanceOfUnderlying
            );
            newDepositedBeans = newDepositedBeans.mul(percentToFill).div(
                C.precision()
            );
        }

        // Calculate how many Beans to add as LP
        uint256 newDepositedLPBeans = amount.mul(C.exploitAddLPRatio()).div(
            DECIMALS
        );
        // Mint the Beans
        C.bean().mint(
            address(this),
            newDepositedBeans.add(newDepositedLPBeans)
        );
        // Add Liquidity
        uint256 newLP = C.curveZap().add_liquidity(
            C.CURVE_BEAN_METAPOOL,
            [newDepositedLPBeans, 0, amount, 0],
            minAmountOut
        );
        // Increment underlying balances of Unripe Tokens
        LibUnripe.incrementUnderlying(C.UNRIPE_BEAN, newDepositedBeans);
        LibUnripe.incrementUnderlying(C.UNRIPE_LP, newLP);

        s.recapitalized = s.recapitalized.add(amount);
    }

    function push(uint128 id) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (s.fFirst == 0) {
            // Queue is empty
            s.season.fertilizing = true;
            s.fLast = id;
            s.fFirst = id;
        } else if (id <= s.fFirst) {
            // Add to front of queue
            setNext(id, s.fFirst);
            s.fFirst = id;
        } else if (id >= s.fLast) {
            // Add to back of queue
            setNext(s.fLast, id);
            s.fLast = id;
        } else {
            // Add to middle of queue
            uint128 prev = s.fFirst;
            uint128 next = getNext(prev);
            // Search for proper place in line
            while (id > next) {
                prev = next;
                next = getNext(next);
            }
            setNext(prev, id);
            setNext(id, next);
        }
    }

    function remainingRecapitalization()
        internal
        view
        returns (uint256 remaining)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 totalDollars = C
            .dollarPerUnripeLP()
            .mul(C.unripeLP().totalSupply())
            .div(DECIMALS);
        totalDollars = totalDollars / 1e6 * 1e6; // round down to nearest USDC
        if (s.recapitalized >= totalDollars) return 0;
        return totalDollars.sub(s.recapitalized);
    }

    function pop() internal returns (bool) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint128 first = s.fFirst;
        s.activeFertilizer = s.activeFertilizer.sub(getAmount(first));
        uint128 next = getNext(first);
        if (next == 0) {
            // If all Unfertilized Beans have been fertilized, delete line.
            require(s.activeFertilizer == 0, "Still active fertilizer");
            s.fFirst = 0;
            s.fLast = 0;
            s.season.fertilizing = false;
            return false;
        }
        s.fFirst = getNext(first);
        return true;
    }

    function getAmount(uint128 id) internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.fertilizer[id];
    }

    function getNext(uint128 id) internal view returns (uint128) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.nextFid[id];
    }

    function setNext(uint128 id, uint128 next) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.nextFid[id] = next;
    }
}

File 37 of 44 : LibIncentive.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {OracleLibrary} from "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";
import {IBlockBasefee} from "../interfaces/IBlockBasefee.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "../C.sol";
import "./Curve/LibCurve.sol";

/**
 * @title LibIncentive
 * @author Publius, Chaikitty, Brean
 * @notice Calculates the reward offered for calling Sunrise, adjusts for current gas & ETH prices,
 * and scales the reward up when the Sunrise is called late.
 */
library LibIncentive {
    using SafeMath for uint256;

    /// @dev The time range over which to consult the Uniswap V3 ETH:USDC pool oracle. Measured in seconds.
    uint32 internal constant PERIOD = 1800; // 30 minutes

    /// @dev The Sunrise reward reaches its maximum after this many blocks elapse.
    uint256 internal constant MAX_BLOCKS_LATE = 25;

    /// @dev Base BEAN reward to cover cost of operating a bot.
    uint256 internal constant BASE_REWARD = 3e6; // 3 BEAN

    /// @dev Max BEAN reward for calling Sunrise.
    uint256 internal constant MAX_REWARD = 100e6; // 100 BEAN

    /// @dev Wei buffer to account for the priority fee.
    uint256 internal constant PRIORITY_FEE_BUFFER = 5e9; // 5e9 wei = 5 gwei

    /// @dev The maximum gas which Beanstalk will pay for a Sunrise transaction.
    uint256 internal constant MAX_SUNRISE_GAS = 500_000; // 500k gas

    /// @dev Accounts for extra gas overhead for completing a Sunrise tranasaction.
    // 21k gas (base cost for a transction) + ~79k gas for other overhead
    uint256 internal constant SUNRISE_GAS_OVERHEAD = 100_000; // 100k gas

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

    /// @dev `sunriseReward` is precomputed in {fracExp} using this precision.
    uint256 private constant FRAC_EXP_PRECISION = 1e18;

    //////////////////// CALCULATE REWARD ////////////////////

    /**
     * @param initialGasLeft The amount of gas left at the start of the transaction
     * @param balances The current balances of the BEAN:3CRV pool returned by {stepOracle}
     * @param blocksLate The number of blocks late that {sunrise()} was called.
     * @dev Calculates Sunrise incentive amount based on current gas prices and a computed
     * BEAN:ETH price. This function is called at the end of {sunriseTo()} after all
     * "step" functions have been executed.
     *
     * Price calculation:
     * `X := BEAN / USD`
     * `Y := ETH / USDC`
     * `Y / X := (ETH/USDC)/(BEAN/USD) := ETH / BEAN` (assuming 1 USD == 1 USDC)
     */
    function determineReward(uint256 initialGasLeft, uint256[2] memory balances, uint256 blocksLate)
        internal
        view
        returns (uint256)
    {

        // Cap the maximum number of blocks late. If the sunrise is later than
        // this, Beanstalk will pay the same amount. Prevents unbounded return value.
        if (blocksLate > MAX_BLOCKS_LATE) {
            blocksLate = MAX_BLOCKS_LATE;
        }

        // If the Bean 3Crv pool is empty, it is impossible to determine the price of Bean. Therefore, return the max reward.
        if (balances[0] == 0 || balances[1] == 0) {
            return fracExp(MAX_REWARD, blocksLate);
        }

        // Gets the current BEAN/USD price based on the Curve pool.
        // In the future, this can be swapped out to another oracle
        uint256 beanUsdPrice = getBeanUsdPrice(balances); // BEAN / USD

        // `getEthUsdcPrice()` has 6 decimal precision
        // Assumption: 1 USDC = 1 USD
        uint256 ethUsdcPrice = getEthUsdcPrice(); // WETH / USDC

        // Calculate ETH/BEAN price using the BEAN/USD price and the ETH/USDC price
        uint256 ethBeanPrice = (ethUsdcPrice.mul(1e6)).div(beanUsdPrice); // WETH / BEAN

        // Sunrise gas overhead includes:
        //  - 21K for base transaction cost
        //  - 29K for calculations following the below line, like {fracExp}
        // Max gas which Beanstalk will pay for = 500K.
        uint256 gasUsed = Math.min(initialGasLeft.sub(gasleft()) + SUNRISE_GAS_OVERHEAD, MAX_SUNRISE_GAS);

        // Calculate the current cost in Wei of `gasUsed` gas.
        // {block_basefee()} returns the base fee of the current block in Wei.
        // Adds a buffer for priority fee.
        uint256 gasCostWei = IBlockBasefee(BASE_FEE_CONTRACT).block_basefee().add(PRIORITY_FEE_BUFFER).mul(gasUsed); // (BASE_FEE
            // + PRIORITY_FEE_BUFFER)
            // * GAS_USED

        // Calculates the Sunrise reward to pay in BEAN.
        uint256 sunriseReward = Math.min(
            BASE_REWARD + gasCostWei.mul(ethBeanPrice).div(1e18), // divide by 1e18 to convert wei to eth
            MAX_REWARD
        );

        // Scale the reward up as the number of blocks after expected sunrise increases.
        // `sunriseReward * (1 + 1/100)^(blocks late * seconds per block)`
        // NOTE: 1.01^(25 * 12) = 19.78, This is the maximum multiplier.
        return fracExp(sunriseReward, blocksLate);
    }

    //////////////////// PRICES ////////////////////

    /**
     * @param balances The current balances of the BEAN:3CRV pool returned by {stepOracle}.
     * @dev Calculate the price of BEAN denominated in USD.
     */
    function getBeanUsdPrice(uint256[2] memory balances) internal view returns (uint256) {
        uint256[2] memory rates = getRates();
        uint256[2] memory xp = LibCurve.getXP(balances, rates);

        uint256 a = C.curveMetapool().A_precise();
        uint256 D = LibCurve.getD(xp, a);

        return LibCurve.getPrice(xp, rates, a, D);
    }

    /**
     * @dev Uses the Uniswap V3 Oracle to get the price of WETH denominated in USDC.
     *
     * {OracleLibrary.getQuoteAtTick} returns an arithmetic mean.
     */
    function getEthUsdcPrice() internal view returns (uint256) {
        (int24 tick,) = OracleLibrary.consult(C.UNIV3_ETH_USDC_POOL, PERIOD); // 1 season tick
        return OracleLibrary.getQuoteAtTick(tick, 1e18, C.WETH, C.USDC);
    }

    function getRates() private view returns (uint256[2] memory) {
        // Decimals will always be 6 because we can only mint beans
        // 10**(36-decimals)
        return [1e30, C.curve3Pool().get_virtual_price()];
    }

    //////////////////// MATH UTILITIES ////////////////////

    /**
     * @dev fraxExp scales up the bean reward based on the blocks late.
     * the formula is beans * (1.01)^(Blocks Late * 12 second block time).
     * since block time is capped at 25 blocks,
     * we only need to check cases 0 - 25
     */
    function fracExp(uint256 beans, uint256 blocksLate) internal pure returns (uint256 scaledSunriseReward) {
        // check most likely case first
        if (blocksLate == 0) {
            return beans;
        }

        // Binary Search
        if (blocksLate < 13) {
            if (blocksLate < 7) {
                if (blocksLate < 4) {
                    if (blocksLate < 2) {
                        // blocksLate == 0 is already checked, thus
                        // blocksLate = 1, 1.01^(1*12)
                        return _scaleReward(beans, 1_126_825_030_131_969_720);
                    }
                    if (blocksLate == 2) {
                        // 1.01^(2*12)
                        return _scaleReward(beans, 1_269_734_648_531_914_468);
                    } else {
                        // blocksLate == 3, 1.01^(3*12)
                        return _scaleReward(beans, 1_430_768_783_591_580_504);
                    }
                }
                if (blocksLate < 6) {
                    if (blocksLate == 4) {
                        return _scaleReward(beans, 1_612_226_077_682_464_366);
                    } else {
                        // blocksLate == 5
                        return _scaleReward(beans, 1_816_696_698_564_090_264);
                    }
                } else {
                    // blocksLate == 6
                    return _scaleReward(beans, 2_047_099_312_100_130_925);
                }
            }
            if (blocksLate < 10) {
                if (blocksLate < 9) {
                    if (blocksLate == 7) {
                        return _scaleReward(beans, 2_306_722_744_040_364_517);
                    } else {
                        // blocksLate == 8
                        return _scaleReward(beans, 2_599_272_925_559_383_624);
                    }
                } else {
                    // blocksLate == 9
                    return _scaleReward(beans, 2_928_925_792_664_665_541);
                }
            }
            if (blocksLate < 12) {
                if (blocksLate == 10) {
                    return _scaleReward(beans, 3_300_386_894_573_665_047);
                } else {
                    // blocksLate == 11
                    return _scaleReward(beans, 3_718_958_561_925_128_091);
                }
            } else {
                // blocksLate == 12
                return _scaleReward(beans, 4_190_615_593_600_829_241);
            }
        }
        if (blocksLate < 19) {
            if (blocksLate < 16) {
                if (blocksLate < 15) {
                    if (blocksLate == 13) {
                        return _scaleReward(beans, 4_722_090_542_530_756_587);
                    } else {
                        // blocksLate == 14
                        return _scaleReward(beans, 5_320_969_817_873_109_037);
                    }
                } else {
                    // blocksLate == 15
                    return _scaleReward(beans, 5_995_801_975_356_167_528);
                }
            }
            if (blocksLate < 18) {
                if (blocksLate == 16) {
                    return _scaleReward(beans, 6_756_219_741_546_037_047);
                } else {
                    // blocksLate == 17
                    return _scaleReward(beans, 7_613_077_513_845_821_874);
                }
            }
            return _scaleReward(beans, 8_578_606_298_936_339_361); // blocksLate == 18
        }
        if (blocksLate < 22) {
            if (blocksLate < 21) {
                if (blocksLate == 19) {
                    return _scaleReward(beans, 9_666_588_301_289_245_846);
                } else {
                    // blocksLate == 20
                    return _scaleReward(beans, 10_892_553_653_873_600_447);
                }
            }
            return _scaleReward(beans, 12_274_002_099_240_216_703); // blocksLate == 21
        }
        if (blocksLate <= 23) {
            if (blocksLate == 22) {
                return _scaleReward(beans, 13_830_652_785_316_216_792);
            } else {
                // blocksLate == 23
                return _scaleReward(beans, 15_584_725_741_558_756_931);
            }
        }
        if (blocksLate >= 25) {
            // block rewards are capped at 25 (MAX_BLOCKS_LATE)
            return _scaleReward(beans, 19_788_466_261_924_388_319);
        } else {
            // blocksLate == 24
            return _scaleReward(beans, 17_561_259_053_330_430_428);
        }
    }

    function _scaleReward(uint256 beans, uint256 scaler) private pure returns (uint256) {
        return beans.mul(scaler).div(FRAC_EXP_PRECISION);
    }
}

File 38 of 44 : LibPRBMath.sol
/**
 * SPDX-License-Identifier: MIT
 **/
 
pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;


/**
 * @title LibPRBMath contains functionality to compute powers of 60.18 unsigned floating point to uint256
 * Solution taken from https://github.com/paulrberg/prb-math/blob/main/contracts/PRBMathUD60x18.sol
 * and adapted to Solidity 0.7.6
**/
library LibPRBMath {

    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    // /// @dev How many trailing decimals can be represented.
    //uint256 internal constant SCALE = 1e18;

    // /// @dev Largest power of two divisor of SCALE.
    // uint256 internal constant SCALE_LPOTD = 262144;

    // /// @dev SCALE inverted mod 2^256.
    // uint256 internal constant SCALE_INVERSE =
    //     78156646155174841979727994598816262306175212592076161876661_508869554232690281;

    
    /// @dev How many trailing decimals can be represented.
    uint256 internal constant SCALE = 1e18;

     /// @dev Half the SCALE number.
    uint256 internal constant HALF_SCALE = 5e17;

    /// @dev Largest power of two divisor of SCALE.
    uint256 internal constant SCALE_LPOTD = 68719476736;

    /// @dev SCALE inverted mod 2^256.
    uint256 internal constant SCALE_INVERSE =
        24147664466589061293728112707504694672000531928996266765558539143717230155537;

    function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {
        // Calculate the first iteration of the loop in advance.
        result = y & 1 > 0 ? x : SCALE;

        // Equivalent to "for(y /= 2; y > 0; y /= 2)" but faster.
        for (y >>= 1; y > 0; y >>= 1) {
            x = mulDivFixedPoint(x, x);

            // Equivalent to "y % 2 == 1" but faster.
            if (y & 1 > 0) {
                result = mulDivFixedPoint(result, x);
            }
        }
    }

    function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {
        uint256 prod0;
        uint256 prod1;
        assembly {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        if (prod1 >= SCALE) {
            revert("fixed point overflow");
        }

        uint256 remainder;
        uint256 roundUpUnit;
        assembly {
            remainder := mulmod(x, y, SCALE)
            roundUpUnit := gt(remainder, 499999999999999999)
        }

        if (prod1 == 0) {
            result = (prod0 / SCALE) + roundUpUnit;
            return result;
        }

        assembly {
            result := add(
                mul(
                    or(
                        div(sub(prod0, remainder), SCALE_LPOTD),
                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))
                    ),
                    SCALE_INVERSE
                ),
                roundUpUnit
            )
        }
    }

    function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {
        if (x >= 2**128) {
            x >>= 128;
            msb += 128;
        }
        if (x >= 2**64) {
            x >>= 64;
            msb += 64;
        }
        if (x >= 2**32) {
            x >>= 32;
            msb += 32;
        }
        if (x >= 2**16) {
            x >>= 16;
            msb += 16;
        }
        if (x >= 2**8) {
            x >>= 8;
            msb += 8;
        }
        if (x >= 2**4) {
            x >>= 4;
            msb += 4;
        }
        if (x >= 2**2) {
            x >>= 2;
            msb += 2;
        }
        if (x >= 2**1) {
            // No need to shift x any more.
            msb += 1;
        }
    }

    function logBase2(uint256 x) internal pure returns (uint256 result) {
        if (x < SCALE) {
            revert("Log Input Too Small");
        }
        // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).
        uint256 n = mostSignificantBit(x / SCALE);

        // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow
        // because n is maximum 255 and SCALE is 1e18.
        result = n * SCALE;

        // This is y = x * 2^(-n).
        uint256 y = x >> n;

        // If y = 1, the fractional part is zero.
        if (y == SCALE) {
            return result;
        }

        // Calculate the fractional part via the iterative approximation.
        // The "delta >>= 1" part is equivalent to "delta /= 2", but shifting bits is faster.
        for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {
            y = (y * y) / SCALE;

            // Is y^2 > 2 and so in the range [2,4)?
            if (y >= 2 * SCALE) {
                // Add the 2^(-m) factor to the logarithm.
                result += delta;

                // Corresponds to z/2 on Wikipedia.
                y >>= 1;
            }
        }
    }

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a <= b ? a : b;
    }

    function min(uint128 a, uint128 b) internal pure returns (uint256) {
        return a <= b ? a : b;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

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

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

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

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

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }
}

File 39 of 44 : 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 40 of 44 : 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 41 of 44 : LibUnripe.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {IBean} from "../interfaces/IBean.sol";
import {AppStorage, LibAppStorage} from "./LibAppStorage.sol";
import {C} from "../C.sol";

/**
 * @title LibUnripe
 * @author Publius
 */
library LibUnripe {
    using SafeMath for uint256;

    event ChangeUnderlying(address indexed token, int256 underlying);

    uint256 constant DECIMALS = 1e6;

    function percentBeansRecapped() internal view returns (uint256 percent) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return
            s.u[C.UNRIPE_BEAN].balanceOfUnderlying.mul(DECIMALS).div(
                C.unripeBean().totalSupply()
            );
    }

    function percentLPRecapped() internal view returns (uint256 percent) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return
            C.unripeLPPerDollar().mul(s.recapitalized).div(
                C.unripeLP().totalSupply()
            );
    }

    function incrementUnderlying(address token, uint256 amount) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.u[token].balanceOfUnderlying = s.u[token].balanceOfUnderlying.add(
            amount
        );
        emit ChangeUnderlying(token, int256(amount));
    }

    function decrementUnderlying(address token, uint256 amount) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.u[token].balanceOfUnderlying = s.u[token].balanceOfUnderlying.sub(
            amount
        );
        emit ChangeUnderlying(token, -int256(amount));
    }

    function unripeToUnderlying(address unripeToken, uint256 unripe)
        internal
        view
        returns (uint256 underlying)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        underlying = s.u[unripeToken].balanceOfUnderlying.mul(unripe).div(
            IBean(unripeToken).totalSupply()
        );
    }

    function underlyingToUnripe(address unripeToken, uint256 underlying)
        internal
        view
        returns (uint256 unripe)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        unripe = IBean(unripeToken).totalSupply().mul(underlying).div(
            s.u[unripeToken].balanceOfUnderlying
        );
    }

    function addUnderlying(address token, uint256 underlying) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (token == C.UNRIPE_LP) {
            uint256 recapped = underlying.mul(s.recapitalized).div(
                s.u[C.UNRIPE_LP].balanceOfUnderlying
            );
            s.recapitalized = s.recapitalized.add(recapped);
        }
        incrementUnderlying(token, underlying);
    }

    function removeUnderlying(address token, uint256 underlying) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (token == C.UNRIPE_LP) {
            uint256 recapped = underlying.mul(s.recapitalized).div(
                s.u[C.UNRIPE_LP].balanceOfUnderlying
            );
            s.recapitalized = s.recapitalized.sub(recapped);
        }
        decrementUnderlying(token, underlying);
    }
}

File 42 of 44 : LibCurveOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "../Curve/LibBeanMetaCurve.sol";
import "../LibAppStorage.sol";
import "../LibSafeMath32.sol";

/**
 * @dev Curve metapool functions used by {LibCurveOracle}. 
 */
interface IMeta3CurveOracle {
    function block_timestamp_last() external view returns (uint256);
    function get_price_cumulative_last() external view returns (uint256[2] memory);
    function get_balances() external view returns (uint256[2] memory);
    function get_previous_balances() external view returns (uint256[2] memory);
}

/**
 * @title Oracle
 * @author Publius, Chaikitty
 * @notice Tracks the TWAP of the BEAN:3CRV Curve Metapool.
 */
library LibCurveOracle {
    using SafeMath for uint256;
    using LibSafeMath32 for uint32;
    
    /* Constrains the deltaB to be +/- 1/X of the current Bean supply */
    uint256 private constant MAX_DELTA_B_DENOMINATOR = 100;

    /**
     * @param season The Season in which the oracle was updated.
     * @param deltaB The deltaB
     * @param balances The TWA 
     */
    event MetapoolOracle(
        uint32 indexed season,
        int256 deltaB,
        uint256[2] balances
    );

    //////////////////// CHECK ////////////////////

    function check() internal view returns (int256 deltaB) {
        deltaB = _check();
        deltaB = checkForMaxDeltaB(deltaB);
    }

    function _check() internal view returns (int256 db) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (s.co.initialized) {
            (db, , ) = twaDeltaB();
        } else {
            db = 0;
        }
    }

    //////////////////// CAPTURE ////////////////////

    function capture() internal returns (int256 deltaB, uint256[2] memory balances) {
        (deltaB, balances) = _capture();
        deltaB = checkForMaxDeltaB(deltaB);
    }

    /** 
     * @dev `balances` stores the TWA balances throughout the Season.
     * In the case of {initializeOracle}, it will be the current balances.
     */
    function _capture() internal returns (int256 deltaB, uint256[2] memory balances) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (s.co.initialized) {
            (deltaB, balances) = updateOracle();
        } else {
            initializeOracle();
            // Since the oracle was just initialized, it is not possible to compute the TWA balances over the Season.
            // Thus, use the previous balances instead.
            balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).get_previous_balances();
        }
    }

    //////////////////// INITIALIZE ////////////////////

    function initializeOracle() internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        Storage.Oracle storage o = s.co;

        uint256[2] memory balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL)
            .get_price_cumulative_last();
        uint256 timestamp = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).block_timestamp_last();
        
        if (balances[0] != 0 && balances[1] != 0 && timestamp != 0) {
            (o.balances, o.timestamp) = getCumulative();
            o.initialized = true;
        }
    }

    function updateOracle() internal returns (int256 deltaB, uint256[2] memory balances) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        (deltaB, balances, s.co.balances) = twaDeltaB();

        emit MetapoolOracle(s.season.current, deltaB, s.co.balances);
        s.co.timestamp = block.timestamp;
    }

    //////////////////// CALCULATIONS ////////////////////

    function twaDeltaB()
        internal
        view
        returns (int256 deltaB, uint256[2] memory balances, uint256[2] memory cum_balances)
    {
        (balances, cum_balances) = twap();
        uint256 d = LibBeanMetaCurve.getDFroms(balances);
        deltaB = LibBeanMetaCurve.getDeltaBWithD(balances[0], d);
    }

    function twap()
        internal
        view
        returns (uint256[2] memory balances, uint256[2] memory cum_balances)
    {
        cum_balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).get_price_cumulative_last();
        balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).get_balances();
        uint256 lastTimestamp = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).block_timestamp_last();

        cum_balances[0] = cum_balances[0].add(
            balances[0].mul(block.timestamp.sub(lastTimestamp))
        );
        cum_balances[1] = cum_balances[1].add(
            balances[1].mul(block.timestamp.sub(lastTimestamp))
        );

        AppStorage storage s = LibAppStorage.diamondStorage();
        Storage.Oracle storage o = s.co;

        uint256 deltaTimestamp = block.timestamp.sub(o.timestamp);

        balances[0] = cum_balances[0].sub(o.balances[0]).div(deltaTimestamp);
        balances[1] = cum_balances[1].sub(o.balances[1]).div(deltaTimestamp);
    }

    function getCumulative()
        private
        view
        returns (uint256[2] memory cum_balances, uint256 lastTimestamp)
    {
        cum_balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).get_price_cumulative_last();
        uint256[2] memory balances = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).get_balances();
        lastTimestamp = IMeta3CurveOracle(C.CURVE_BEAN_METAPOOL).block_timestamp_last();

        cum_balances[0] = cum_balances[0].add(
            balances[0].mul(block.timestamp.sub(lastTimestamp))
        );
        cum_balances[1] = cum_balances[1].add(
            balances[1].mul(block.timestamp.sub(lastTimestamp))
        );
        lastTimestamp = block.timestamp;
    }

    /**
     * @dev Constrain `deltaB` to be less than +/- 1% of the total supply of Bean.
     * 
     * `1% = 1/MAX_DELTA_B_DENOMINATOR`
     */
    function checkForMaxDeltaB(int256 deltaB) private view returns (int256) {
        int256 maxDeltaB = int256(C.bean().totalSupply().div(MAX_DELTA_B_DENOMINATOR));
        if (deltaB < 0) return deltaB > -maxDeltaB ? deltaB : -maxDeltaB;
        return deltaB < maxDeltaB ? deltaB : maxDeltaB;
    }
}

File 43 of 44 : LibBalance.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;
pragma experimental ABIEncoderV2;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/math/Math.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/SafeCast.sol";
import {AppStorage, LibAppStorage} from "../LibAppStorage.sol";

/**
 * @title LibInternalBalance
 * @author LeoFib, Publius
 * @notice Handles internal read/write functions for Internal User Balances.
 * Largely inspired by Balancer's Vault.
 */
library LibBalance {
    using SafeERC20 for IERC20;
    using SafeMath for uint256;
    using SafeCast for uint256;

    /**
     * @notice Emitted when an account's Internal Balance changes.
     * @param account The account whose balance changed.
     * @param token Which token balance changed.
     * @param delta The amount the balance increased (if positive) or decreased (if negative).
     */
    event InternalBalanceChanged(
        address indexed account,
        IERC20 indexed token,
        int256 delta
    );

    /**
     * @dev Returns the sum of `account`'s Internal and External (ERC20) balance of `token`
     */
    function getBalance(address account, IERC20 token)
        internal
        view
        returns (uint256 balance)
    {
        balance = token.balanceOf(account).add(
            getInternalBalance(account, token)
        );
        return balance;
    }

    /**
     * @dev Increases `account`'s Internal Balance of `token` by `amount`.
     */
    function increaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount
    ) internal {
        uint256 currentBalance = getInternalBalance(account, token);
        uint256 newBalance = currentBalance.add(amount);
        setInternalBalance(account, token, newBalance, amount.toInt256());
    }

    /**
     * @dev Decreases `account`'s Internal Balance of `token` by `amount`. If `allowPartial` is true, this function
     * doesn't revert if `account` doesn't have enough balance, and sets it to zero and returns the deducted amount
     * instead.
     */
    function decreaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount,
        bool allowPartial
    ) internal returns (uint256 deducted) {
        uint256 currentBalance = getInternalBalance(account, token);
        require(
            allowPartial || (currentBalance >= amount),
            "Balance: Insufficient internal balance"
        );

        deducted = Math.min(currentBalance, amount);
        // By construction, `deducted` is lower or equal to `currentBalance`, 
        // so we don't need to use checked arithmetic.
        uint256 newBalance = currentBalance - deducted;
        setInternalBalance(account, token, newBalance, -(deducted.toInt256()));
    }

    /**
     * @dev Sets `account`'s Internal Balance of `token` to `newBalance`.
     *
     * Emits an {InternalBalanceChanged} event. This event includes `delta`, which is the amount the balance increased
     * (if positive) or decreased (if negative). To avoid reading the current balance in order to compute the delta,
     * this function relies on the caller providing it directly.
     */
    function setInternalBalance(
        address account,
        IERC20 token,
        uint256 newBalance,
        int256 delta
    ) private {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.internalTokenBalance[account][token] = newBalance;
        emit InternalBalanceChanged(account, token, delta);
    }

    /**
     * @dev Returns `account`'s Internal Balance of `token`.
     */
    function getInternalBalance(address account, IERC20 token)
        internal
        view
        returns (uint256 balance)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        balance = s.internalTokenBalance[account][token];
    }
}

File 44 of 44 : LibTransfer.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../../interfaces/IBean.sol";
import "./LibBalance.sol";

/**
 * @title LibTransfer
 * @author Publius
 * @notice Handles the recieving and sending of Tokens to/from internal Balances.
 */
library LibTransfer {
    using SafeERC20 for IERC20;
    using SafeMath for uint256;

    enum From {
        EXTERNAL,
        INTERNAL,
        EXTERNAL_INTERNAL,
        INTERNAL_TOLERANT
    }
    enum To {
        EXTERNAL,
        INTERNAL
    }

    function transferToken(
        IERC20 token,
        address sender,
        address recipient,
        uint256 amount,
        From fromMode,
        To toMode
    ) internal returns (uint256 transferredAmount) {
        if (fromMode == From.EXTERNAL && toMode == To.EXTERNAL) {
            uint256 beforeBalance = token.balanceOf(recipient);
            token.safeTransferFrom(sender, recipient, amount);
            return token.balanceOf(recipient).sub(beforeBalance);
        }
        amount = receiveToken(token, amount, sender, fromMode);
        sendToken(token, amount, recipient, toMode);
        return amount;
    }

    function receiveToken(
        IERC20 token,
        uint256 amount,
        address sender,
        From mode
    ) internal returns (uint256 receivedAmount) {
        if (amount == 0) return 0;
        if (mode != From.EXTERNAL) {
            receivedAmount = LibBalance.decreaseInternalBalance(
                sender,
                token,
                amount,
                mode != From.INTERNAL
            );
            if (amount == receivedAmount || mode == From.INTERNAL_TOLERANT)
                return receivedAmount;
        }
        uint256 beforeBalance = token.balanceOf(address(this));
        token.safeTransferFrom(sender, address(this), amount - receivedAmount);
        return
            receivedAmount.add(
                token.balanceOf(address(this)).sub(beforeBalance)
            );
    }

    function sendToken(
        IERC20 token,
        uint256 amount,
        address recipient,
        To mode
    ) internal {
        if (amount == 0) return;
        if (mode == To.INTERNAL)
            LibBalance.increaseInternalBalance(recipient, token, amount);
        else token.safeTransfer(recipient, amount);
    }

    function burnToken(
        IBean token,
        uint256 amount,
        address sender,
        From mode
    ) internal returns (uint256 burnt) {
        // burnToken only can be called with Unripe Bean, Unripe Bean:3Crv or Bean token, which are all Beanstalk tokens.
        // Beanstalk's ERC-20 implementation uses OpenZeppelin's ERC20Burnable
        // which reverts if burnFrom function call cannot burn full amount.
        if (mode == From.EXTERNAL) {
            token.burnFrom(sender, amount);
            burnt = amount;
        } else {
            burnt = LibTransfer.receiveToken(token, amount, sender, mode);
            token.burn(burnt);
        }
    }

    function mintToken(
        IBean token,
        uint256 amount,
        address recipient,
        To mode
    ) internal {
        if (mode == To.EXTERNAL) {
            token.mint(recipient, amount);
        } else {
            token.mint(address(this), amount);
            LibTransfer.sendToken(token, amount, recipient, mode);
        }
    }
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"beans","type":"uint256"}],"name":"Incentivization","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"season","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"toField","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toSilo","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toFertilizer","type":"uint256"}],"name":"Reward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toField","type":"uint256"}],"name":"SeasonOfPlenty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"season","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"soil","type":"uint256"}],"name":"Soil","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"}],"name":"Sunrise","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"season","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"caseId","type":"uint256"},{"indexed":false,"internalType":"int8","name":"change","type":"int8"}],"name":"WeatherChange","type":"event"},{"inputs":[],"name":"abovePeg","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"enum LibTransfer.To","name":"mode","type":"uint8"}],"name":"gm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"season","type":"uint32"}],"name":"plentyPerRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"poolDeltaB","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rain","outputs":[{"components":[{"internalType":"uint256","name":"deprecated","type":"uint256"},{"internalType":"uint256","name":"pods","type":"uint256"},{"internalType":"uint256","name":"roots","type":"uint256"}],"internalType":"struct Storage.Rain","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"season","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"seasonTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sunrise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"sunriseBlock","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"time","outputs":[{"components":[{"internalType":"uint32","name":"current","type":"uint32"},{"internalType":"uint32","name":"lastSop","type":"uint32"},{"internalType":"uint8","name":"withdrawSeasons","type":"uint8"},{"internalType":"uint32","name":"lastSopSeason","type":"uint32"},{"internalType":"uint32","name":"rainStart","type":"uint32"},{"internalType":"bool","name":"raining","type":"bool"},{"internalType":"bool","name":"fertilizing","type":"bool"},{"internalType":"uint32","name":"sunriseBlock","type":"uint32"},{"internalType":"bool","name":"abovePeg","type":"bool"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct Storage.Season","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDeltaB","outputs":[{"internalType":"int256","name":"deltaB","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weather","outputs":[{"components":[{"internalType":"uint256[2]","name":"deprecated","type":"uint256[2]"},{"internalType":"uint128","name":"lastDSoil","type":"uint128"},{"internalType":"uint32","name":"lastSowTime","type":"uint32"},{"internalType":"uint32","name":"thisSowTime","type":"uint32"},{"internalType":"uint32","name":"t","type":"uint32"}],"internalType":"struct Storage.Weather","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50614279806100206000396000f3fe6080604052600436106100d25760003560e01c80635c975abb1161007f578063c50b0fb011610059578063c50b0fb0146101f4578063ca7b7d7b14610209578063e60d7a831461021e578063fc06d2a61461023e576100d2565b80635c975abb146101aa57806364ee4b80146101bf578063686b6159146101d2576100d2565b80633b2ecb70116100b05780633b2ecb701461014657806343def26e14610168578063471bcdbe1461018a576100d2565b806306c499d8146100d757806316ada547146101025780632a27c49914610124575b600080fd5b3480156100e357600080fd5b506100ec610246565b6040516100f99190613e43565b60405180910390f35b34801561010e57600080fd5b50610117610255565b6040516100f99190614012565b34801561013057600080fd5b5061013961032b565b6040516100f99190613e38565b34801561015257600080fd5b5061015b61033b565b6040516100f99190614199565b34801561017457600080fd5b5061017d61034e565b6040516100f99190613ff1565b34801561019657600080fd5b506100ec6101a5366004613cfb565b61037b565b3480156101b657600080fd5b506101396103d7565b6100ec6101cd366004613d15565b6103e0565b3480156101de57600080fd5b506101e761048b565b6040516100f991906140e8565b34801561020057600080fd5b5061015b610518565b34801561021557600080fd5b5061015b610524565b34801561022a57600080fd5b506100ec610239366004613de4565b610560565b6100ec610578565b6000610250610585565b905090565b61025d613baf565b50604080516101808101825260035463ffffffff808216835264010000000082048116602084015260ff6801000000000000000083048116948401949094526901000000000000000000820481166060840152600160681b820481166080840152600160881b82048416151560a0840152720100000000000000000000000000000000000082048416151560c0840152600160981b82041660e0830152600160b81b900490911615156101008201526004546101208201526005546101408201526006546101608201525b90565b600354600160b81b900460ff1690565b600354600160981b900463ffffffff1690565b610356613c13565b506040805160608101825260185481526019546020820152601a549181019190915290565b60006001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee4914156103b1576103aa610585565b90506103d2565b60405162461bcd60e51b81526004016103c990613ea7565b60405180910390fd5b919050565b60025460ff1690565b6000805a90506103ee6103d7565b1561040b5760405162461bcd60e51b81526004016103c990613f4c565b610413610518565b63ffffffff16610421610524565b63ffffffff16116104445760405162461bcd60e51b81526004016103c990613ede565b61044c61059a565b600080610457610627565b91509150600061046683610642565b90506104728382610a67565b61047e87858489610abe565b9450505050505b92915050565b610493613c34565b6040805160e08101909152601f8160a081018260028282826020028201915b8154815260200190600101908083116104b2575050509183525050600291909101546001600160801b038116602083015263ffffffff600160801b820481166040840152600160a01b820481166060840152600160c01b90910416608090910152905090565b60035463ffffffff1690565b60045460009042101561053957506000610328565b60055461054b575063ffffffff610328565b60055460045442038161055a57fe5b04905090565b63ffffffff166000908152603d602052604090205490565b60006102503360006103e0565b600061058f610b71565b905061025081610ba8565b426006556003805463ffffffff198116600163ffffffff928316018216177fffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffff16600160981b4392909216919091021790556105f3610518565b63ffffffff167fb360bcf4b60112f485fd94b599df45181250ef0e80538be7b334728ab0990b1a60405160405180910390a2565b6000610631613c69565b610639610c66565b90939092509050565b60008061064d610c8c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561068557600080fd5b505afa158015610699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bd9190613dcc565b9050806106e35750506021805463ffffffff60c01b1916600160c01b17905560086103d2565b600e54600c546000916106ff916106f991610ca4565b83610d01565b600b80546001600160801b03808216909255919250600160801b90910416610725613c87565b60215463ffffffff600160a01b909104811610156108a757602154600160801b900463ffffffff908116148061076c5750602154610258600160a01b90910463ffffffff16105b806107c55750602154603c600160801b90910463ffffffff161180156107c557506021546107ad9063ffffffff600160801b909104811690603c90610d3016565b60215463ffffffff918216600160a01b909104909116105b156107e2576107db670de0b6b3a7640000610d93565b9050610830565b6021546108029063ffffffff600160801b909104811690603c90610dc116565b60215463ffffffff918216600160a01b90910490911611610825576107db610e24565b61082d610e46565b90505b602180547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff600160801b63ffffffff600160a01b8404160273ffffffff0000000000000000000000000000000019909216919091171677ffffffff0000000000000000000000000000000000000000179055610937565b6021546001600160801b0316826108c7576108c0610e46565b91506108ea565b806108dd576108c0670de0b6b3a7640000610d93565b6108e78382610d01565b91505b602154600160801b900463ffffffff90811614610935576021805473ffffffff00000000000000000000000000000000191673ffffffff000000000000000000000000000000001790555b505b6000945061095661094f6703782dace9d90000610e61565b8490610e7b565b1561096457601894506109a3565b61097861094f670214e8348c4f0000610e61565b1561098657601094506109a3565b61099961094f66b1a2bc2ec50000610e61565b156109a357600894505b60008613806109d15750851580156109d157506109d16109ca670214e8348c4f0000610e61565b8490610e90565b156109dd576004850194505b6109f86109f1670e92596fd6290000610e61565b8290610e7b565b15610a0857600285019450610a28565b610a1c6109f1670d2f13f7789f0000610e61565b15610a28576001850194505b602180546fffffffffffffffffffffffffffffffff19166001600160801b038416179055610a5585610ea6565b610a5e85610fc2565b50505050919050565b6000821315610aa0576000610a7b836110fd565b9050610a87818361121d565b506003805460ff60b81b1916600160b81b179055610aba565b610aac826000036112b0565b6003805460ff60b81b191690555b5050565b600080610b00600c610afa610af3610aea610ad7610518565b6005549063ffffffff9081169061131b16565b60045490611374565b4290610ca4565b906113ce565b90506000610b0f868684611435565b9050610b24610b1c610c8c565b8289876115a3565b866001600160a01b03167fbb4f656853bc420ad6e4321622c07eefb4ed40e3f91b35553ce14a6dff4c098182604051610b5d9190613e43565b60405180910390a29150505b949350505050565b600080610b7c61168e565b601481015490915060ff1615610b9f57610b94611693565b50909250610ba49050565b600091505b5090565b600080610c286064610bb8610c8c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afa9190613dcc565b90506000831215610c5057806000038313610c465780600003610c48565b825b9150506103d2565b808312610c5d5780610c5f565b825b9392505050565b6000610c70613c69565b610c786116d9565b9092509050610c8682610ba8565b91509091565b73bea0000029ad1c77d3d5d23ba2d8893db9d1efab90565b600082821115610cfb576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b610d09613c87565b6040518060200160405280610d2785670de0b6b3a7640000866117a3565b90529392505050565b60008263ffffffff168263ffffffff161115610cfb576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b610d9b613c87565b604080516020810190915280610db984670de0b6b3a764000061131b565b905292915050565b600082820163ffffffff8085169082161015610c5f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b610e2c613c87565b506040805160208101909152670de0b6b3a7640000815290565b610e4e613c87565b5060408051602081019091526000815290565b610e69613c87565b50604080516020810190915290815290565b600080610e8884846117b3565b119392505050565b60006002610e9e84846117b3565b109392505050565b600060018260208110610eb557fe5b602081049190910154602154601f9092166101000a9004600090810b9250600160c01b90910463ffffffff169082810b1215610f52578160000360000b63ffffffff168163ffffffff1611610f26576021805463ffffffff60c01b1916600160c01b17905560018190039150610f4d565b6021805463ffffffff60c01b1916600160c01b6000858103900b840363ffffffff16021790555b610f77565b6021805463ffffffff60c01b1916600160c01b600085900b840163ffffffff16021790555b60035460405163ffffffff909116907f0a45556f9791e291dc4f0b1ef18464f43f40ed88e389ebc91d42435adb0b46e790610fb59086908690614164565b60405180910390a2505050565b6004811080610fd15750600781115b1561100957600354600160881b900460ff1615611004576003805471ff0000000000000000000000000000000000191690555b6110fa565b600354600160881b900460ff166110a55760038054600160881b71ff00000000000000000000000000000000001990911617808255600160681b80820463ffffffff9081166000908152603d602052604080822054948316825290209290925582547fffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffff8116921602179055600c54601955601d54601a556110fa565b6003546110d89063ffffffff600160681b820481169160001960ff680100000000000000009092048216011690610dc116565b60035463ffffffff9182169116106110fa57601a54156110fa576110fa6117e5565b50565b600080611108610c8c565b6001600160a01b03166340c10f1930856040518363ffffffff1660e01b8152600401611135929190613e1f565b600060405180830381600087803b15801561114f57600080fd5b505af1158015611163573d6000803e3d6000fd5b50506003547201000000000000000000000000000000000000900460ff161591506111a2905057611193836119ed565b905061119f8382610ca4565b92505b600c54600e5410156111c6576111b783611b5e565b91506111c38383610ca4565b92505b6111cf83611b9e565b60035460405163ffffffff909116907f037e6634327a51e2bae1af6cf38c4d1cc3f7c97706d4ffa1936e5bfc84201a489061120f90859087908690614183565b60405180910390a250919050565b60215460009061124990606463ffffffff600160c01b90920482168101821691610afa91879161131b16565b90506018821061127857611271670de0b6b3a7640000610afa836706f05b59d3b2000061131b565b90506112a2565b60088210156112a25761129f670de0b6b3a7640000610afa836714d1120d7b16000061131b565b90505b6112ab816112b0565b505050565b600b80546fffffffffffffffffffffffffffffffff19166001600160801b03831617905560035460405163ffffffff909116907f120fa8f6031fee45346a5c55083305b3840521c041af94971694219f7c26db8b90611310908490613e43565b60405180910390a250565b60008261132a57506000610485565b8282028284828161133757fe5b0414610c5f5760405162461bcd60e51b81526004018080602001828103825260218152602001806141d16021913960400191505060405180910390fd5b600082820183811015610c5f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000808211611424576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161142d57fe5b049392505050565b6000601982111561144557601991505b8251158061145557506020830151155b1561146f576114686305f5e10083611c54565b9050610c5f565b600061147a84611f02565b90506000611486611fbd565b9050600061149b83610afa84620f424061131b565b905060006114bb620186a06114b15a8b90610ca4565b016207a120612025565b9050600061155d8261155764012a05f2007384292919cb64b590c0131550483707e43ef223ac6001600160a01b03166358d755556040518163ffffffff1660e01b815260040160206040518083038186803b15801561151957600080fd5b505afa15801561152d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115519190613dcc565b90611374565b9061131b565b9050600061158961157a670de0b6b3a7640000610afa858861131b565b622dc6c0016305f5e100612025565b90506115958189611c54565b9a9950505050505050505050565b60008160018111156115b157fe5b141561161c576040516340c10f1960e01b81526001600160a01b038516906340c10f19906115e59085908790600401613e1f565b600060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b50505050611688565b6040516340c10f1960e01b81526001600160a01b038516906340c10f199061164a9030908790600401613e1f565b600060405180830381600087803b15801561166457600080fd5b505af1158015611678573d6000803e3d6000fd5b5050505061168884848484612034565b50505050565b600090565b600061169d613c69565b6116a5613c69565b6116ad612076565b909250905060006116bd836122dd565b90506116d18360005b602002015182612303565b935050909192565b60006116e3613c69565b60006116ed61168e565b601481015490915060ff161561170f57611705612313565b909350915061179e565b61171761239c565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b031663d96c7fce6040518163ffffffff1660e01b8152600401604080518083038186803b15801561176357600080fd5b505afa158015611777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179b9190613d4e565b91505b509091565b6000610b6982610afa868661131b565b8051825160009114156117c857506001610485565b81518351116117d85760006117db565b60025b60ff169392505050565b60006117ef612517565b9050600081136117ff57506119eb565b601954600e548291600091101561189d5750600e54601954819003906118259082611374565b600e55611830610c8c565b6001600160a01b03166340c10f19306118498486611374565b6040518363ffffffff1660e01b8152600401611866929190613e1f565b600060405180830381600087803b15801561188057600080fd5b505af1158015611894573d6000803e3d6000fd5b50505050611905565b6118a5610c8c565b6001600160a01b03166340c10f1930846040518363ffffffff1660e01b81526004016118d2929190613e1f565b600060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b505050505b600061190f6125b2565b6001600160a01b0316633df02124600060018660006040518563ffffffff1660e01b81526004016119439493929190613e84565b602060405180830381600087803b15801561195d57600080fd5b505af1158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190613dcc565b90506119a0816125ca565b60035460405163ffffffff909116907f197f686c11daefde9cd3a4b8a2494b7405fd240b540fca948ab00a0d2dcc1758906119de9084908690614175565b60405180910390a2505050505b565b6000806119fb8360036113ce565b604354909150600090611a0f9083906113ce565b6047549091506001600160801b03166000611a2a8284611374565b6046549091506001600160801b03165b808210611b0b57611a4b8184610ca4565b604354909450611a6790611a6090869061131b565b8790611374565b9550611a71612682565b611ad557604780546fffffffffffffffffffffffffffffffff19166001600160801b038316179055604454611aa69087611374565b604481905560455414611acb5760405162461bcd60e51b81526004016103c990613f15565b50505050506103d2565b604354611ae690610afa8789610ca4565b9350915081611af58185611374565b6046549092506001600160801b03169050611a3a565b604780546fffffffffffffffffffffffffffffffff19166001600160801b038416179055604354611b4190611a6090869061131b565b604454909650611b519087611374565b6044555050505050919050565b600e54600c546000919003611b748360026113ce565b9150808211611b835781611b85565b805b600e54909250611b959083611374565b600e5550919050565b611bb6611bad8261271061131b565b601b5490611374565b601b55602254611bc69082611374565b60225573bea0000029ad1c77d3d5d23ba2d8893db9d1efab60005260386020527f783e9dbd7ada0882f5e75946cdc58b9d3ff5bb4329ad861a80e70f123144955454611c129082611374565b73bea0000029ad1c77d3d5d23ba2d8893db9d1efab60005260386020527f783e9dbd7ada0882f5e75946cdc58b9d3ff5bb4329ad861a80e70f12314495545550565b600081611c62575081610485565b600d821015611dad576007821015611d14576004821015611ccc576002821015611c9f57611c9883670fa349650d08eeb8612773565b9050610485565b8160021415611cba57611c988367119f00ef7cc00ee4612773565b611c98836713db1ca0cdb1a358612773565b6006821015611d02578160041415611cf057611c988367165fc71361e2766e612773565b611c98836719363405a6899998612773565b611c9883671c68c1fa75acc06d612773565b600a821015611d65576009821015611d53578160071415611d4157611c9883672003201d39d719e5612773565b611c988367241278f44a41e648612773565b611c98836728a5a27d8541bdc5612773565b600c821015611d9b5781600a1415611d8957611c9883672dcd5464f86afb17612773565b611c988367339c651bb1f1df9b612773565b611c9883673a280eadf6ca4739612773565b6013821015611e4f576010821015611e0757600f821015611df55781600d1415611de357611c98836741883c5468c6ffeb612773565b611c98836749d7e1db8ee6d02d612773565b611c98836753355e2124b09568612773565b6012821015611e3d578160101415611e2b57611c9883675dc2ea0f17553f37612773565b611c98836769a715a9bc4b51b2612773565b611c988367770d54fa3c076ba1612773565b6016821015611ea0576015821015611e8e578160131415611e7c57611c98836786269ed8204acc96612773565b611c988367972a1fd64404e7bf612773565b611c988367aa5603e0f99ca87f612773565b60178211611ed5578160161415611ec357611c988367bff0596e288a3fd8612773565b611c988367d848117d937ef643612773565b60198210611ef057611c98836801129ec138afce1ddf612773565b611c988367f3b62010c25f79dc612773565b600080611f0d61278b565b90506000611f1b8483612830565b90506000611f276125b2565b6001600160a01b03166376a2f0f06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f5f57600080fd5b505afa158015611f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f979190613dcc565b90506000611fa58383612880565b9050611fb38385848461298c565b9695505050505050565b600080611fe0738ad599c3a0ff1de082011efddc58f1908eb6e6d86107086129cc565b50905061201f81670de0b6b3a764000073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48612d8d565b91505090565b6000818310610c5d5781610c5f565b8261203e57611688565b600181600181111561204c57fe5b14156120625761205d828585612e84565b611688565b6116886001600160a01b0385168385612ebb565b61207e613c69565b612086613c69565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b1580156120d257600080fd5b505afa1580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a9190613d4e565b905073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561215857600080fd5b505afa15801561216c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121909190613d4e565b9150600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b1580156121e157600080fd5b505afa1580156121f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122199190613dcc565b905061224961223a61222b4284610ca4565b8560005b60200201519061131b565b8360005b602002015190611374565b825261226b61226361225b4284610ca4565b85600161222f565b83600161223e565b6020830152600061227a61168e565b60178101549091506014820190600090612295904290610ca4565b90506122b581610afa60018501600001548860005b602002015190610ca4565b865260028201546122ce908290610afa908860016122aa565b60208701525093949293505050565b600061048573c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee498364e8d4a51000612f3b565b64e8d4a510006002909104040390565b600061231d613c69565b600061232761168e565b9050612331611693565b61234060158501826002613c9a565b5050600383015460405192955090935063ffffffff16907f0e0c101fa6afb12838450cfd752d904d70198349367ff256b1460f10bcbd1904906123899086906015860190613e4c565b60405180910390a2426017909101559091565b60006123a661168e565b90506000816014019050600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b1580156123fe57600080fd5b505afa158015612412573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124369190613d4e565b9050600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b15801561248757600080fd5b505afa15801561249b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bf9190613dcc565b8251909150158015906124d55750602082015115155b80156124e057508015155b15611688576124ed612fc0565b6003850181905561250360018601836002613c9a565b5050835460ff191660011784555050505050565b6000806125226125b2565b6001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561255957600080fd5b505afa15801561256d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125919190613d4e565b9050600061259e826122dd565b90506125ab8260006116c6565b9250505090565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee4990565b601a54612613906125e990610afa8469d3c21bcecceda100000061131b565b60035463ffffffff64010000000090910481166000908152603d6020526040902054919061137416565b6003805463ffffffff600160681b9182900481166000908152603d60205260409020939093558154690100000000000000000064010000000092820485169290920267ffffffff000000001990911617928316026cffffffff0000000000000000001990921691909117905550565b60008061268d61168e565b60468101549091506001600160801b03166126b56126aa826131ae565b604384015490610ca4565b604383015560006126c5826131dd565b90506001600160801b038116612734576043830154156126f75760405162461bcd60e51b81526004016103c990613f83565b5050600060468201819055600390910180547fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff1690559050610328565b61273d826131dd565b60469390930180546fffffffffffffffffffffffffffffffff19166001600160801b039094169390931790925550600192915050565b6000610c5f670de0b6b3a7640000610afa858561131b565b612793613c69565b60405180604001604052806c0c9f2c9cd04674edea4000000081526020016127b961320f565b6001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b1580156127f157600080fd5b505afa158015612805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128299190613dcc565b9052905090565b612838613c69565b815161285490670de0b6b3a764000090610afa9086600061222f565b8152602082015161287590670de0b6b3a764000090610afa9086600161222f565b602082015292915050565b6000806000805b60028110156128ae5785816002811061289c57fe5b60200201519290920191600101612887565b50816128bf57600092505050610485565b90915081906002840260005b610100811015612973578460005b600281101561290b5760028982600281106128f057fe5b6020020151028783028161290057fe5b0491506001016128d9565b50859350600381026064606319850186020401866002830260648689020401028161293257fe5b04955083861180156129475750600184870311155b15612956575050505050610485565b60018685031161296a575050505050610485565b506001016128cb565b5060405162461bcd60e51b81526004016103c990613fba565b82518451600091670de0b6b3a7640000900401816129ac82888787613227565b60209790970151620f424097900360001901969096049695505050505050565b60008063ffffffff8316612a27576040805162461bcd60e51b815260206004820152600260248201527f4250000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612a5657fe5b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612a7f57fe5b63ffffffff9092166020928302919091018201526040517f883bdbfd0000000000000000000000000000000000000000000000000000000081526004810182815283516024830152835160009384936001600160a01b038b169363883bdbfd9388939192839260449091019185820191028083838b5b83811015612b0d578181015183820152602001612af5565b505050509050019250505060006040518083038186803b158015612b3057600080fd5b505afa158015612b44573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015612b6d57600080fd5b8101908080516040519392919084640100000000821115612b8d57600080fd5b908301906020820185811115612ba257600080fd5b8251866020820283011164010000000082111715612bbf57600080fd5b82525081516020918201928201910280838360005b83811015612bec578181015183820152602001612bd4565b5050505090500160405260200180516040519392919084640100000000821115612c1557600080fd5b908301906020820185811115612c2a57600080fd5b8251866020820283011164010000000082111715612c4757600080fd5b82525081516020918201928201910280838360005b83811015612c74578181015183820152602001612c5c565b5050505090500160405250505091509150600082600081518110612c9457fe5b602002602001015183600181518110612ca957fe5b6020026020010151039050600082600081518110612cc357fe5b602002602001015183600181518110612cd857fe5b60200260200101510390508763ffffffff168260060b81612cf557fe5b05965060008260060b128015612d1f57508763ffffffff168260060b81612d1857fe5b0760060b15155b15612d2c57600019909601955b63ffffffff88166001600160a01b030277ffffffffffffffffffffffffffffffffffffffff00000000602083901b1677ffffffffffffffffffffffffffffffffffffffffffffffff821681612d7d57fe5b0496505050505050509250929050565b600080612d998661331e565b90506001600160801b036001600160a01b03821611612e08576001600160a01b0380821680029084811690861610612de857612de3600160c01b876001600160801b03168361366c565b612e00565b612e0081876001600160801b0316600160c01b61366c565b925050612e7b565b6000612e276001600160a01b038316806801000000000000000061366c565b9050836001600160a01b0316856001600160a01b031610612e5f57612e5a600160801b876001600160801b03168361366c565b612e77565b612e7781876001600160801b0316600160801b61366c565b9250505b50949350505050565b6000612e90848461371b565b90506000612e9e8284611374565b9050612eb4858583612eaf87613756565b6137b6565b5050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112ab908490613831565b6000610b69612f4a84846138e2565b856001600160a01b03166376a2f0f06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f8357600080fd5b505afa158015612f97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbb9190613dcc565b612880565b612fc8613c69565b600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b15801561301657600080fd5b505afa15801561302a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304e9190613d4e565b9150600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561309e57600080fd5b505afa1580156130b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d69190613d4e565b905073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b15801561312557600080fd5b505afa158015613139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315d9190613dcc565b915061317f61317761316f4285610ca4565b83600061222f565b84600061223e565b83526131a16131996131914285610ca4565b83600161222f565b84600161223e565b6020840152509091429150565b6000806131b961168e565b6001600160801b038416600090815260419091016020526040902054915050919050565b6000806131e861168e565b6001600160801b038085166000908152604290920160205260409091205416915050919050565b73bebc44782c7db0a1a60cb6fe97d0b483032ff1c790565b60008080808460028702825b600281101561328c5780613249578a945061326e565b600181146132695789816002811061325d57fe5b6020020151945061326e565b613284565b94840194600285028389028161328057fe5b0492505b600101613233565b50600281026064888402028161329e57fe5b04915060008160648902816132af57fe5b048601905087965060005b60ff81101561297357879450888289600202010384898a0201816132da57fe5b04975084881180156132ef5750600185890311155b156133005750505050505050610b69565b6001888603116133165750505050505050610b69565b6001016132ba565b60008060008360020b12613335578260020b61333d565b8260020b6000035b9050620d89e8811115613397576040805162461bcd60e51b815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000600182166133ab57600160801b6133bd565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff16905060028216156133f1576ffff97272373d413259a46990580e213a0260801c5b6004821615613410576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561342f576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b601082161561344e576fffcb9843d60f6159c9db58835c9266440260801c5b602082161561346d576fff973b41fa98c081472e6896dfb254c00260801c5b604082161561348c576fff2ea16466c96a3843ec78b326b528610260801c5b60808216156134ab576ffe5dee046a99a2a811c461f1969c30530260801c5b6101008216156134cb576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b6102008216156134eb576ff987a7253ac413176f2b074cf7815e540260801c5b61040082161561350b576ff3392b0822b70005940c7a398e4b70f30260801c5b61080082161561352b576fe7159475a2c29b7443b29c7fa6e889d90260801c5b61100082161561354b576fd097f3bdfd2022b8845ad8f792aa58250260801c5b61200082161561356b576fa9f746462d870fdf8a65dc1f90e061e50260801c5b61400082161561358b576f70d869a156d2a1b890bb3df62baf32f70260801c5b6180008216156135ab576f31be135f97d08fd981231505542fcfa60260801c5b620100008216156135cc576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b620200008216156135ec576e5d6af8dedb81196699c329225ee6040260801c5b6204000082161561360b576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613628576b048a170391f7dc42444e8fa20260801c5b60008460020b131561364357806000198161363f57fe5b0490505b64010000000081061561365757600161365a565b60005b60ff16602082901c0192505050919050565b60008080600019858709868602925082811090839003039050806136a2576000841161369757600080fd5b508290049050610c5f565b8084116136ae57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b60008061372661168e565b6001600160a01b039485166000908152603e90910160209081526040808320959096168252939093525050205490565b60007f80000000000000000000000000000000000000000000000000000000000000008210610ba45760405162461bcd60e51b81526004018080602001828103825260288152602001806141f26028913960400191505060405180910390fd5b60006137c061168e565b6001600160a01b038087166000818152603e840160209081526040808320948a1680845294909152908190208790555192935090917f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c4290613822908690613e43565b60405180910390a35050505050565b6000613886826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661396c9092919063ffffffff16565b8051909150156112ab578080602001905160208110156138a557600080fd5b50516112ab5760405162461bcd60e51b815260040180806020018281038252602a81526020018061421a602a913960400191505060405180910390fd5b6138ea613c69565b610c5f83836138f761320f565b6001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b15801561392f57600080fd5b505afa158015613943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139679190613dcc565b61397b565b6060610b6984846000856139b5565b613983613c69565b61398f8385600061222f565b81526139a9670de0b6b3a7640000610afa8487600161222f565b60208201529392505050565b6060824710156139f65760405162461bcd60e51b81526004018080602001828103825260268152602001806141ab6026913960400191505060405180910390fd5b6139ff85613b05565b613a50576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310613a8e5780518252601f199092019160209182019101613a6f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613af0576040519150601f19603f3d011682016040523d82523d6000602084013e613af5565b606091505b5091509150612e77828286613b0b565b3b151590565b60608315613b1a575081610c5f565b825115613b2a5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b74578181015183820152602001613b5c565b50505050905090810190601f168015613ba15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a00160405280613c47613c69565b8152600060208201819052604082018190526060820181905260809091015290565b60405180604001604052806002906020820280368337509192915050565b6040518060200160405280600081525090565b8260028101928215613cc8579160200282015b82811115613cc8578251825591602001919060010190613cad565b50610ba49291505b80821115610ba45760008155600101613cd0565b80356001600160a01b03811681146103d257600080fd5b600060208284031215613d0c578081fd5b610c5f82613ce4565b60008060408385031215613d27578081fd5b613d3083613ce4565b9150602083013560028110613d43578182fd5b809150509250929050565b600060408284031215613d5f578081fd5b82601f830112613d6d578081fd5b6040516040810181811067ffffffffffffffff82111715613d8a57fe5b8060405250808385604086011115613da0578384fd5b835b6002811015613dc1578151835260209283019290910190600101613da2565b509195945050505050565b600060208284031215613ddd578081fd5b5051919050565b600060208284031215613df5578081fd5b813563ffffffff81168114610c5f578182fd5b15159052565b63ffffffff169052565b60ff169052565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b8281526060810160208083018460005b6002811015613e7957815483529183019160019182019101613e5c565b505050509392505050565b600f94850b81529290930b60208301526040820152606081019190915260800190565b6020808252601a908201527f4f7261636c653a20506f6f6c206e6f7420737570706f72746564000000000000604082015260600190565b6020808252601d908201527f536561736f6e3a205374696c6c2063757272656e7420536561736f6e2e000000604082015260600190565b6020808252600c908201527f5061696420213d206f7765640000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f536561736f6e3a205061757365642e0000000000000000000000000000000000604082015260600190565b60208082526017908201527f5374696c6c206163746976652066657274696c697a6572000000000000000000604082015260600190565b60208082526018908201527f50726963653a20436f6e76657267656e63652066616c73650000000000000000604082015260600190565b81518152602080830151908201526040918201519181019190915260600190565b600061018082019050614026828451613e0e565b60208301516140386020840182613e0e565b50604083015161404b6040840182613e18565b50606083015161405e6060840182613e0e565b5060808301516140716080840182613e0e565b5060a083015161408460a0840182613e08565b5060c083015161409760c0840182613e08565b5060e08301516140aa60e0840182613e0e565b50610100808401516140be82850182613e08565b50506101208381015190830152610140808401519083015261016092830151929091019190915290565b815160c08201908260005b60028110156141125782518252602092830192909101906001016140f3565b5050506001600160801b03602084015116604083015263ffffffff6040840151166060830152606083015161414a6080840182613e0e565b50608083015161415d60a0840182613e0e565b5092915050565b91825260000b602082015260400190565b918252602082015260400190565b9283526020830191909152604082015260600190565b63ffffffff9190911681526020019056fe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220bbb692d91077149fc143c3e3b7eee1e89192dd254e74e9535d3c99903db9ac4e64736f6c63430007060033

Deployed Bytecode

0x6080604052600436106100d25760003560e01c80635c975abb1161007f578063c50b0fb011610059578063c50b0fb0146101f4578063ca7b7d7b14610209578063e60d7a831461021e578063fc06d2a61461023e576100d2565b80635c975abb146101aa57806364ee4b80146101bf578063686b6159146101d2576100d2565b80633b2ecb70116100b05780633b2ecb701461014657806343def26e14610168578063471bcdbe1461018a576100d2565b806306c499d8146100d757806316ada547146101025780632a27c49914610124575b600080fd5b3480156100e357600080fd5b506100ec610246565b6040516100f99190613e43565b60405180910390f35b34801561010e57600080fd5b50610117610255565b6040516100f99190614012565b34801561013057600080fd5b5061013961032b565b6040516100f99190613e38565b34801561015257600080fd5b5061015b61033b565b6040516100f99190614199565b34801561017457600080fd5b5061017d61034e565b6040516100f99190613ff1565b34801561019657600080fd5b506100ec6101a5366004613cfb565b61037b565b3480156101b657600080fd5b506101396103d7565b6100ec6101cd366004613d15565b6103e0565b3480156101de57600080fd5b506101e761048b565b6040516100f991906140e8565b34801561020057600080fd5b5061015b610518565b34801561021557600080fd5b5061015b610524565b34801561022a57600080fd5b506100ec610239366004613de4565b610560565b6100ec610578565b6000610250610585565b905090565b61025d613baf565b50604080516101808101825260035463ffffffff808216835264010000000082048116602084015260ff6801000000000000000083048116948401949094526901000000000000000000820481166060840152600160681b820481166080840152600160881b82048416151560a0840152720100000000000000000000000000000000000082048416151560c0840152600160981b82041660e0830152600160b81b900490911615156101008201526004546101208201526005546101408201526006546101608201525b90565b600354600160b81b900460ff1690565b600354600160981b900463ffffffff1690565b610356613c13565b506040805160608101825260185481526019546020820152601a549181019190915290565b60006001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee4914156103b1576103aa610585565b90506103d2565b60405162461bcd60e51b81526004016103c990613ea7565b60405180910390fd5b919050565b60025460ff1690565b6000805a90506103ee6103d7565b1561040b5760405162461bcd60e51b81526004016103c990613f4c565b610413610518565b63ffffffff16610421610524565b63ffffffff16116104445760405162461bcd60e51b81526004016103c990613ede565b61044c61059a565b600080610457610627565b91509150600061046683610642565b90506104728382610a67565b61047e87858489610abe565b9450505050505b92915050565b610493613c34565b6040805160e08101909152601f8160a081018260028282826020028201915b8154815260200190600101908083116104b2575050509183525050600291909101546001600160801b038116602083015263ffffffff600160801b820481166040840152600160a01b820481166060840152600160c01b90910416608090910152905090565b60035463ffffffff1690565b60045460009042101561053957506000610328565b60055461054b575063ffffffff610328565b60055460045442038161055a57fe5b04905090565b63ffffffff166000908152603d602052604090205490565b60006102503360006103e0565b600061058f610b71565b905061025081610ba8565b426006556003805463ffffffff198116600163ffffffff928316018216177fffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffff16600160981b4392909216919091021790556105f3610518565b63ffffffff167fb360bcf4b60112f485fd94b599df45181250ef0e80538be7b334728ab0990b1a60405160405180910390a2565b6000610631613c69565b610639610c66565b90939092509050565b60008061064d610c8c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561068557600080fd5b505afa158015610699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106bd9190613dcc565b9050806106e35750506021805463ffffffff60c01b1916600160c01b17905560086103d2565b600e54600c546000916106ff916106f991610ca4565b83610d01565b600b80546001600160801b03808216909255919250600160801b90910416610725613c87565b60215463ffffffff600160a01b909104811610156108a757602154600160801b900463ffffffff908116148061076c5750602154610258600160a01b90910463ffffffff16105b806107c55750602154603c600160801b90910463ffffffff161180156107c557506021546107ad9063ffffffff600160801b909104811690603c90610d3016565b60215463ffffffff918216600160a01b909104909116105b156107e2576107db670de0b6b3a7640000610d93565b9050610830565b6021546108029063ffffffff600160801b909104811690603c90610dc116565b60215463ffffffff918216600160a01b90910490911611610825576107db610e24565b61082d610e46565b90505b602180547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff600160801b63ffffffff600160a01b8404160273ffffffff0000000000000000000000000000000019909216919091171677ffffffff0000000000000000000000000000000000000000179055610937565b6021546001600160801b0316826108c7576108c0610e46565b91506108ea565b806108dd576108c0670de0b6b3a7640000610d93565b6108e78382610d01565b91505b602154600160801b900463ffffffff90811614610935576021805473ffffffff00000000000000000000000000000000191673ffffffff000000000000000000000000000000001790555b505b6000945061095661094f6703782dace9d90000610e61565b8490610e7b565b1561096457601894506109a3565b61097861094f670214e8348c4f0000610e61565b1561098657601094506109a3565b61099961094f66b1a2bc2ec50000610e61565b156109a357600894505b60008613806109d15750851580156109d157506109d16109ca670214e8348c4f0000610e61565b8490610e90565b156109dd576004850194505b6109f86109f1670e92596fd6290000610e61565b8290610e7b565b15610a0857600285019450610a28565b610a1c6109f1670d2f13f7789f0000610e61565b15610a28576001850194505b602180546fffffffffffffffffffffffffffffffff19166001600160801b038416179055610a5585610ea6565b610a5e85610fc2565b50505050919050565b6000821315610aa0576000610a7b836110fd565b9050610a87818361121d565b506003805460ff60b81b1916600160b81b179055610aba565b610aac826000036112b0565b6003805460ff60b81b191690555b5050565b600080610b00600c610afa610af3610aea610ad7610518565b6005549063ffffffff9081169061131b16565b60045490611374565b4290610ca4565b906113ce565b90506000610b0f868684611435565b9050610b24610b1c610c8c565b8289876115a3565b866001600160a01b03167fbb4f656853bc420ad6e4321622c07eefb4ed40e3f91b35553ce14a6dff4c098182604051610b5d9190613e43565b60405180910390a29150505b949350505050565b600080610b7c61168e565b601481015490915060ff1615610b9f57610b94611693565b50909250610ba49050565b600091505b5090565b600080610c286064610bb8610c8c565b6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afa9190613dcc565b90506000831215610c5057806000038313610c465780600003610c48565b825b9150506103d2565b808312610c5d5780610c5f565b825b9392505050565b6000610c70613c69565b610c786116d9565b9092509050610c8682610ba8565b91509091565b73bea0000029ad1c77d3d5d23ba2d8893db9d1efab90565b600082821115610cfb576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b610d09613c87565b6040518060200160405280610d2785670de0b6b3a7640000866117a3565b90529392505050565b60008263ffffffff168263ffffffff161115610cfb576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b610d9b613c87565b604080516020810190915280610db984670de0b6b3a764000061131b565b905292915050565b600082820163ffffffff8085169082161015610c5f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b610e2c613c87565b506040805160208101909152670de0b6b3a7640000815290565b610e4e613c87565b5060408051602081019091526000815290565b610e69613c87565b50604080516020810190915290815290565b600080610e8884846117b3565b119392505050565b60006002610e9e84846117b3565b109392505050565b600060018260208110610eb557fe5b602081049190910154602154601f9092166101000a9004600090810b9250600160c01b90910463ffffffff169082810b1215610f52578160000360000b63ffffffff168163ffffffff1611610f26576021805463ffffffff60c01b1916600160c01b17905560018190039150610f4d565b6021805463ffffffff60c01b1916600160c01b6000858103900b840363ffffffff16021790555b610f77565b6021805463ffffffff60c01b1916600160c01b600085900b840163ffffffff16021790555b60035460405163ffffffff909116907f0a45556f9791e291dc4f0b1ef18464f43f40ed88e389ebc91d42435adb0b46e790610fb59086908690614164565b60405180910390a2505050565b6004811080610fd15750600781115b1561100957600354600160881b900460ff1615611004576003805471ff0000000000000000000000000000000000191690555b6110fa565b600354600160881b900460ff166110a55760038054600160881b71ff00000000000000000000000000000000001990911617808255600160681b80820463ffffffff9081166000908152603d602052604080822054948316825290209290925582547fffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffff8116921602179055600c54601955601d54601a556110fa565b6003546110d89063ffffffff600160681b820481169160001960ff680100000000000000009092048216011690610dc116565b60035463ffffffff9182169116106110fa57601a54156110fa576110fa6117e5565b50565b600080611108610c8c565b6001600160a01b03166340c10f1930856040518363ffffffff1660e01b8152600401611135929190613e1f565b600060405180830381600087803b15801561114f57600080fd5b505af1158015611163573d6000803e3d6000fd5b50506003547201000000000000000000000000000000000000900460ff161591506111a2905057611193836119ed565b905061119f8382610ca4565b92505b600c54600e5410156111c6576111b783611b5e565b91506111c38383610ca4565b92505b6111cf83611b9e565b60035460405163ffffffff909116907f037e6634327a51e2bae1af6cf38c4d1cc3f7c97706d4ffa1936e5bfc84201a489061120f90859087908690614183565b60405180910390a250919050565b60215460009061124990606463ffffffff600160c01b90920482168101821691610afa91879161131b16565b90506018821061127857611271670de0b6b3a7640000610afa836706f05b59d3b2000061131b565b90506112a2565b60088210156112a25761129f670de0b6b3a7640000610afa836714d1120d7b16000061131b565b90505b6112ab816112b0565b505050565b600b80546fffffffffffffffffffffffffffffffff19166001600160801b03831617905560035460405163ffffffff909116907f120fa8f6031fee45346a5c55083305b3840521c041af94971694219f7c26db8b90611310908490613e43565b60405180910390a250565b60008261132a57506000610485565b8282028284828161133757fe5b0414610c5f5760405162461bcd60e51b81526004018080602001828103825260218152602001806141d16021913960400191505060405180910390fd5b600082820183811015610c5f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000808211611424576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161142d57fe5b049392505050565b6000601982111561144557601991505b8251158061145557506020830151155b1561146f576114686305f5e10083611c54565b9050610c5f565b600061147a84611f02565b90506000611486611fbd565b9050600061149b83610afa84620f424061131b565b905060006114bb620186a06114b15a8b90610ca4565b016207a120612025565b9050600061155d8261155764012a05f2007384292919cb64b590c0131550483707e43ef223ac6001600160a01b03166358d755556040518163ffffffff1660e01b815260040160206040518083038186803b15801561151957600080fd5b505afa15801561152d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115519190613dcc565b90611374565b9061131b565b9050600061158961157a670de0b6b3a7640000610afa858861131b565b622dc6c0016305f5e100612025565b90506115958189611c54565b9a9950505050505050505050565b60008160018111156115b157fe5b141561161c576040516340c10f1960e01b81526001600160a01b038516906340c10f19906115e59085908790600401613e1f565b600060405180830381600087803b1580156115ff57600080fd5b505af1158015611613573d6000803e3d6000fd5b50505050611688565b6040516340c10f1960e01b81526001600160a01b038516906340c10f199061164a9030908790600401613e1f565b600060405180830381600087803b15801561166457600080fd5b505af1158015611678573d6000803e3d6000fd5b5050505061168884848484612034565b50505050565b600090565b600061169d613c69565b6116a5613c69565b6116ad612076565b909250905060006116bd836122dd565b90506116d18360005b602002015182612303565b935050909192565b60006116e3613c69565b60006116ed61168e565b601481015490915060ff161561170f57611705612313565b909350915061179e565b61171761239c565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b031663d96c7fce6040518163ffffffff1660e01b8152600401604080518083038186803b15801561176357600080fd5b505afa158015611777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179b9190613d4e565b91505b509091565b6000610b6982610afa868661131b565b8051825160009114156117c857506001610485565b81518351116117d85760006117db565b60025b60ff169392505050565b60006117ef612517565b9050600081136117ff57506119eb565b601954600e548291600091101561189d5750600e54601954819003906118259082611374565b600e55611830610c8c565b6001600160a01b03166340c10f19306118498486611374565b6040518363ffffffff1660e01b8152600401611866929190613e1f565b600060405180830381600087803b15801561188057600080fd5b505af1158015611894573d6000803e3d6000fd5b50505050611905565b6118a5610c8c565b6001600160a01b03166340c10f1930846040518363ffffffff1660e01b81526004016118d2929190613e1f565b600060405180830381600087803b1580156118ec57600080fd5b505af1158015611900573d6000803e3d6000fd5b505050505b600061190f6125b2565b6001600160a01b0316633df02124600060018660006040518563ffffffff1660e01b81526004016119439493929190613e84565b602060405180830381600087803b15801561195d57600080fd5b505af1158015611971573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119959190613dcc565b90506119a0816125ca565b60035460405163ffffffff909116907f197f686c11daefde9cd3a4b8a2494b7405fd240b540fca948ab00a0d2dcc1758906119de9084908690614175565b60405180910390a2505050505b565b6000806119fb8360036113ce565b604354909150600090611a0f9083906113ce565b6047549091506001600160801b03166000611a2a8284611374565b6046549091506001600160801b03165b808210611b0b57611a4b8184610ca4565b604354909450611a6790611a6090869061131b565b8790611374565b9550611a71612682565b611ad557604780546fffffffffffffffffffffffffffffffff19166001600160801b038316179055604454611aa69087611374565b604481905560455414611acb5760405162461bcd60e51b81526004016103c990613f15565b50505050506103d2565b604354611ae690610afa8789610ca4565b9350915081611af58185611374565b6046549092506001600160801b03169050611a3a565b604780546fffffffffffffffffffffffffffffffff19166001600160801b038416179055604354611b4190611a6090869061131b565b604454909650611b519087611374565b6044555050505050919050565b600e54600c546000919003611b748360026113ce565b9150808211611b835781611b85565b805b600e54909250611b959083611374565b600e5550919050565b611bb6611bad8261271061131b565b601b5490611374565b601b55602254611bc69082611374565b60225573bea0000029ad1c77d3d5d23ba2d8893db9d1efab60005260386020527f783e9dbd7ada0882f5e75946cdc58b9d3ff5bb4329ad861a80e70f123144955454611c129082611374565b73bea0000029ad1c77d3d5d23ba2d8893db9d1efab60005260386020527f783e9dbd7ada0882f5e75946cdc58b9d3ff5bb4329ad861a80e70f12314495545550565b600081611c62575081610485565b600d821015611dad576007821015611d14576004821015611ccc576002821015611c9f57611c9883670fa349650d08eeb8612773565b9050610485565b8160021415611cba57611c988367119f00ef7cc00ee4612773565b611c98836713db1ca0cdb1a358612773565b6006821015611d02578160041415611cf057611c988367165fc71361e2766e612773565b611c98836719363405a6899998612773565b611c9883671c68c1fa75acc06d612773565b600a821015611d65576009821015611d53578160071415611d4157611c9883672003201d39d719e5612773565b611c988367241278f44a41e648612773565b611c98836728a5a27d8541bdc5612773565b600c821015611d9b5781600a1415611d8957611c9883672dcd5464f86afb17612773565b611c988367339c651bb1f1df9b612773565b611c9883673a280eadf6ca4739612773565b6013821015611e4f576010821015611e0757600f821015611df55781600d1415611de357611c98836741883c5468c6ffeb612773565b611c98836749d7e1db8ee6d02d612773565b611c98836753355e2124b09568612773565b6012821015611e3d578160101415611e2b57611c9883675dc2ea0f17553f37612773565b611c98836769a715a9bc4b51b2612773565b611c988367770d54fa3c076ba1612773565b6016821015611ea0576015821015611e8e578160131415611e7c57611c98836786269ed8204acc96612773565b611c988367972a1fd64404e7bf612773565b611c988367aa5603e0f99ca87f612773565b60178211611ed5578160161415611ec357611c988367bff0596e288a3fd8612773565b611c988367d848117d937ef643612773565b60198210611ef057611c98836801129ec138afce1ddf612773565b611c988367f3b62010c25f79dc612773565b600080611f0d61278b565b90506000611f1b8483612830565b90506000611f276125b2565b6001600160a01b03166376a2f0f06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f5f57600080fd5b505afa158015611f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f979190613dcc565b90506000611fa58383612880565b9050611fb38385848461298c565b9695505050505050565b600080611fe0738ad599c3a0ff1de082011efddc58f1908eb6e6d86107086129cc565b50905061201f81670de0b6b3a764000073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48612d8d565b91505090565b6000818310610c5d5781610c5f565b8261203e57611688565b600181600181111561204c57fe5b14156120625761205d828585612e84565b611688565b6116886001600160a01b0385168385612ebb565b61207e613c69565b612086613c69565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b1580156120d257600080fd5b505afa1580156120e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210a9190613d4e565b905073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561215857600080fd5b505afa15801561216c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121909190613d4e565b9150600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b1580156121e157600080fd5b505afa1580156121f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122199190613dcc565b905061224961223a61222b4284610ca4565b8560005b60200201519061131b565b8360005b602002015190611374565b825261226b61226361225b4284610ca4565b85600161222f565b83600161223e565b6020830152600061227a61168e565b60178101549091506014820190600090612295904290610ca4565b90506122b581610afa60018501600001548860005b602002015190610ca4565b865260028201546122ce908290610afa908860016122aa565b60208701525093949293505050565b600061048573c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee498364e8d4a51000612f3b565b64e8d4a510006002909104040390565b600061231d613c69565b600061232761168e565b9050612331611693565b61234060158501826002613c9a565b5050600383015460405192955090935063ffffffff16907f0e0c101fa6afb12838450cfd752d904d70198349367ff256b1460f10bcbd1904906123899086906015860190613e4c565b60405180910390a2426017909101559091565b60006123a661168e565b90506000816014019050600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b1580156123fe57600080fd5b505afa158015612412573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124369190613d4e565b9050600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b15801561248757600080fd5b505afa15801561249b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124bf9190613dcc565b8251909150158015906124d55750602082015115155b80156124e057508015155b15611688576124ed612fc0565b6003850181905561250360018601836002613c9a565b5050835460ff191660011784555050505050565b6000806125226125b2565b6001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561255957600080fd5b505afa15801561256d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125919190613d4e565b9050600061259e826122dd565b90506125ab8260006116c6565b9250505090565b73c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee4990565b601a54612613906125e990610afa8469d3c21bcecceda100000061131b565b60035463ffffffff64010000000090910481166000908152603d6020526040902054919061137416565b6003805463ffffffff600160681b9182900481166000908152603d60205260409020939093558154690100000000000000000064010000000092820485169290920267ffffffff000000001990911617928316026cffffffff0000000000000000001990921691909117905550565b60008061268d61168e565b60468101549091506001600160801b03166126b56126aa826131ae565b604384015490610ca4565b604383015560006126c5826131dd565b90506001600160801b038116612734576043830154156126f75760405162461bcd60e51b81526004016103c990613f83565b5050600060468201819055600390910180547fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff1690559050610328565b61273d826131dd565b60469390930180546fffffffffffffffffffffffffffffffff19166001600160801b039094169390931790925550600192915050565b6000610c5f670de0b6b3a7640000610afa858561131b565b612793613c69565b60405180604001604052806c0c9f2c9cd04674edea4000000081526020016127b961320f565b6001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b1580156127f157600080fd5b505afa158015612805573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128299190613dcc565b9052905090565b612838613c69565b815161285490670de0b6b3a764000090610afa9086600061222f565b8152602082015161287590670de0b6b3a764000090610afa9086600161222f565b602082015292915050565b6000806000805b60028110156128ae5785816002811061289c57fe5b60200201519290920191600101612887565b50816128bf57600092505050610485565b90915081906002840260005b610100811015612973578460005b600281101561290b5760028982600281106128f057fe5b6020020151028783028161290057fe5b0491506001016128d9565b50859350600381026064606319850186020401866002830260648689020401028161293257fe5b04955083861180156129475750600184870311155b15612956575050505050610485565b60018685031161296a575050505050610485565b506001016128cb565b5060405162461bcd60e51b81526004016103c990613fba565b82518451600091670de0b6b3a7640000900401816129ac82888787613227565b60209790970151620f424097900360001901969096049695505050505050565b60008063ffffffff8316612a27576040805162461bcd60e51b815260206004820152600260248201527f4250000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612a5657fe5b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612a7f57fe5b63ffffffff9092166020928302919091018201526040517f883bdbfd0000000000000000000000000000000000000000000000000000000081526004810182815283516024830152835160009384936001600160a01b038b169363883bdbfd9388939192839260449091019185820191028083838b5b83811015612b0d578181015183820152602001612af5565b505050509050019250505060006040518083038186803b158015612b3057600080fd5b505afa158015612b44573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040908152811015612b6d57600080fd5b8101908080516040519392919084640100000000821115612b8d57600080fd5b908301906020820185811115612ba257600080fd5b8251866020820283011164010000000082111715612bbf57600080fd5b82525081516020918201928201910280838360005b83811015612bec578181015183820152602001612bd4565b5050505090500160405260200180516040519392919084640100000000821115612c1557600080fd5b908301906020820185811115612c2a57600080fd5b8251866020820283011164010000000082111715612c4757600080fd5b82525081516020918201928201910280838360005b83811015612c74578181015183820152602001612c5c565b5050505090500160405250505091509150600082600081518110612c9457fe5b602002602001015183600181518110612ca957fe5b6020026020010151039050600082600081518110612cc357fe5b602002602001015183600181518110612cd857fe5b60200260200101510390508763ffffffff168260060b81612cf557fe5b05965060008260060b128015612d1f57508763ffffffff168260060b81612d1857fe5b0760060b15155b15612d2c57600019909601955b63ffffffff88166001600160a01b030277ffffffffffffffffffffffffffffffffffffffff00000000602083901b1677ffffffffffffffffffffffffffffffffffffffffffffffff821681612d7d57fe5b0496505050505050509250929050565b600080612d998661331e565b90506001600160801b036001600160a01b03821611612e08576001600160a01b0380821680029084811690861610612de857612de3600160c01b876001600160801b03168361366c565b612e00565b612e0081876001600160801b0316600160c01b61366c565b925050612e7b565b6000612e276001600160a01b038316806801000000000000000061366c565b9050836001600160a01b0316856001600160a01b031610612e5f57612e5a600160801b876001600160801b03168361366c565b612e77565b612e7781876001600160801b0316600160801b61366c565b9250505b50949350505050565b6000612e90848461371b565b90506000612e9e8284611374565b9050612eb4858583612eaf87613756565b6137b6565b5050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112ab908490613831565b6000610b69612f4a84846138e2565b856001600160a01b03166376a2f0f06040518163ffffffff1660e01b815260040160206040518083038186803b158015612f8357600080fd5b505afa158015612f97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbb9190613dcc565b612880565b612fc8613c69565b600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b0316634469e30e6040518163ffffffff1660e01b8152600401604080518083038186803b15801561301657600080fd5b505afa15801561302a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304e9190613d4e565b9150600073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166314f059796040518163ffffffff1660e01b8152600401604080518083038186803b15801561309e57600080fd5b505afa1580156130b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130d69190613d4e565b905073c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee496001600160a01b03166363543f066040518163ffffffff1660e01b815260040160206040518083038186803b15801561312557600080fd5b505afa158015613139573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315d9190613dcc565b915061317f61317761316f4285610ca4565b83600061222f565b84600061223e565b83526131a16131996131914285610ca4565b83600161222f565b84600161223e565b6020840152509091429150565b6000806131b961168e565b6001600160801b038416600090815260419091016020526040902054915050919050565b6000806131e861168e565b6001600160801b038085166000908152604290920160205260409091205416915050919050565b73bebc44782c7db0a1a60cb6fe97d0b483032ff1c790565b60008080808460028702825b600281101561328c5780613249578a945061326e565b600181146132695789816002811061325d57fe5b6020020151945061326e565b613284565b94840194600285028389028161328057fe5b0492505b600101613233565b50600281026064888402028161329e57fe5b04915060008160648902816132af57fe5b048601905087965060005b60ff81101561297357879450888289600202010384898a0201816132da57fe5b04975084881180156132ef5750600185890311155b156133005750505050505050610b69565b6001888603116133165750505050505050610b69565b6001016132ba565b60008060008360020b12613335578260020b61333d565b8260020b6000035b9050620d89e8811115613397576040805162461bcd60e51b815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000600182166133ab57600160801b6133bd565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff16905060028216156133f1576ffff97272373d413259a46990580e213a0260801c5b6004821615613410576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b600882161561342f576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b601082161561344e576fffcb9843d60f6159c9db58835c9266440260801c5b602082161561346d576fff973b41fa98c081472e6896dfb254c00260801c5b604082161561348c576fff2ea16466c96a3843ec78b326b528610260801c5b60808216156134ab576ffe5dee046a99a2a811c461f1969c30530260801c5b6101008216156134cb576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b6102008216156134eb576ff987a7253ac413176f2b074cf7815e540260801c5b61040082161561350b576ff3392b0822b70005940c7a398e4b70f30260801c5b61080082161561352b576fe7159475a2c29b7443b29c7fa6e889d90260801c5b61100082161561354b576fd097f3bdfd2022b8845ad8f792aa58250260801c5b61200082161561356b576fa9f746462d870fdf8a65dc1f90e061e50260801c5b61400082161561358b576f70d869a156d2a1b890bb3df62baf32f70260801c5b6180008216156135ab576f31be135f97d08fd981231505542fcfa60260801c5b620100008216156135cc576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b620200008216156135ec576e5d6af8dedb81196699c329225ee6040260801c5b6204000082161561360b576d2216e584f5fa1ea926041bedfe980260801c5b62080000821615613628576b048a170391f7dc42444e8fa20260801c5b60008460020b131561364357806000198161363f57fe5b0490505b64010000000081061561365757600161365a565b60005b60ff16602082901c0192505050919050565b60008080600019858709868602925082811090839003039050806136a2576000841161369757600080fd5b508290049050610c5f565b8084116136ae57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b60008061372661168e565b6001600160a01b039485166000908152603e90910160209081526040808320959096168252939093525050205490565b60007f80000000000000000000000000000000000000000000000000000000000000008210610ba45760405162461bcd60e51b81526004018080602001828103825260288152602001806141f26028913960400191505060405180910390fd5b60006137c061168e565b6001600160a01b038087166000818152603e840160209081526040808320948a1680845294909152908190208790555192935090917f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c4290613822908690613e43565b60405180910390a35050505050565b6000613886826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661396c9092919063ffffffff16565b8051909150156112ab578080602001905160208110156138a557600080fd5b50516112ab5760405162461bcd60e51b815260040180806020018281038252602a81526020018061421a602a913960400191505060405180910390fd5b6138ea613c69565b610c5f83836138f761320f565b6001600160a01b031663bb7b8b806040518163ffffffff1660e01b815260040160206040518083038186803b15801561392f57600080fd5b505afa158015613943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139679190613dcc565b61397b565b6060610b6984846000856139b5565b613983613c69565b61398f8385600061222f565b81526139a9670de0b6b3a7640000610afa8487600161222f565b60208201529392505050565b6060824710156139f65760405162461bcd60e51b81526004018080602001828103825260268152602001806141ab6026913960400191505060405180910390fd5b6139ff85613b05565b613a50576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310613a8e5780518252601f199092019160209182019101613a6f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613af0576040519150601f19603f3d011682016040523d82523d6000602084013e613af5565b606091505b5091509150612e77828286613b0b565b3b151590565b60608315613b1a575081610c5f565b825115613b2a5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613b74578181015183820152602001613b5c565b50505050905090810190601f168015613ba15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a00160405280613c47613c69565b8152600060208201819052604082018190526060820181905260809091015290565b60405180604001604052806002906020820280368337509192915050565b6040518060200160405280600081525090565b8260028101928215613cc8579160200282015b82811115613cc8578251825591602001919060010190613cad565b50610ba49291505b80821115610ba45760008155600101613cd0565b80356001600160a01b03811681146103d257600080fd5b600060208284031215613d0c578081fd5b610c5f82613ce4565b60008060408385031215613d27578081fd5b613d3083613ce4565b9150602083013560028110613d43578182fd5b809150509250929050565b600060408284031215613d5f578081fd5b82601f830112613d6d578081fd5b6040516040810181811067ffffffffffffffff82111715613d8a57fe5b8060405250808385604086011115613da0578384fd5b835b6002811015613dc1578151835260209283019290910190600101613da2565b509195945050505050565b600060208284031215613ddd578081fd5b5051919050565b600060208284031215613df5578081fd5b813563ffffffff81168114610c5f578182fd5b15159052565b63ffffffff169052565b60ff169052565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b8281526060810160208083018460005b6002811015613e7957815483529183019160019182019101613e5c565b505050509392505050565b600f94850b81529290930b60208301526040820152606081019190915260800190565b6020808252601a908201527f4f7261636c653a20506f6f6c206e6f7420737570706f72746564000000000000604082015260600190565b6020808252601d908201527f536561736f6e3a205374696c6c2063757272656e7420536561736f6e2e000000604082015260600190565b6020808252600c908201527f5061696420213d206f7765640000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f536561736f6e3a205061757365642e0000000000000000000000000000000000604082015260600190565b60208082526017908201527f5374696c6c206163746976652066657274696c697a6572000000000000000000604082015260600190565b60208082526018908201527f50726963653a20436f6e76657267656e63652066616c73650000000000000000604082015260600190565b81518152602080830151908201526040918201519181019190915260600190565b600061018082019050614026828451613e0e565b60208301516140386020840182613e0e565b50604083015161404b6040840182613e18565b50606083015161405e6060840182613e0e565b5060808301516140716080840182613e0e565b5060a083015161408460a0840182613e08565b5060c083015161409760c0840182613e08565b5060e08301516140aa60e0840182613e0e565b50610100808401516140be82850182613e08565b50506101208381015190830152610140808401519083015261016092830151929091019190915290565b815160c08201908260005b60028110156141125782518252602092830192909101906001016140f3565b5050506001600160801b03602084015116604083015263ffffffff6040840151166060830152606083015161414a6080840182613e0e565b50608083015161415d60a0840182613e0e565b5092915050565b91825260000b602082015260400190565b918252602082015260400190565b9283526020830191909152604082015260600190565b63ffffffff9190911681526020019056fe416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220bbb692d91077149fc143c3e3b7eee1e89192dd254e74e9535d3c99903db9ac4e64736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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