ETH Price: $3,156.93 (+3.24%)
Gas: 7 Gwei

Contract

0x141209527F95540E0B018E56EDf5a59E1339437F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60806040176149062023-07-03 17:25:35292 days ago1688405135IN
 Create: MigrationFacet
0 ETH0.076844532.32550237

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MigrationFacet

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000 runs

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

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import "contracts/C.sol";
import "../ReentrancyGuard.sol";
import "./SiloFacet/Silo.sol";
import "./SiloFacet/TokenSilo.sol";
import "contracts/libraries/Silo/LibSilo.sol";
import "contracts/libraries/Silo/LibTokenSilo.sol";
import "contracts/libraries/Silo/LibLegacyTokenSilo.sol";
import "contracts/libraries/Convert/LibConvert.sol";
import "contracts/libraries/LibSafeMath32.sol";

/**
 * @author pizzaman1337
 * @title Handles Migration related functions for the new Silo
 **/
contract MigrationFacet is ReentrancyGuard {

    /** 
     * @notice Migrates farmer's deposits from old (seasons based) to new silo (stems based).
     * @param account Address of the account to migrate
     * @param tokens Array of tokens to migrate
     * @param seasons The seasons in which the deposits were made
     * @param amounts The amounts of those deposits which are to be migrated
     *
     *
     * @dev When migrating an account, you must submit all of the account's deposits,
     * or the migration will not pass because the seed check will fail. The seed check
     * adds up the BDV of all submitted deposits, and multiples by the corresponding
     * seed amount for each token type, then compares that to the total seeds stored for that user.
     * If everything matches, we know all deposits were submitted, and the migration is valid.
     *
     * Deposits are migrated to the stem storage system on a 1:1 basis. Accounts with
     * lots of deposits may take a considerable amount of gas to migrate.
     */
    function mowAndMigrate(
        address account, 
        address[] calldata tokens, 
        uint32[][] calldata seasons,
        uint256[][] calldata amounts,
        uint256 stalkDiff,
        uint256 seedsDiff,
        bytes32[] calldata proof
    ) external payable {
        uint256 seedsVariance = LibLegacyTokenSilo._mowAndMigrate(account, tokens, seasons, amounts);
        //had to break up the migration function into two parts to avoid stack too deep errors
        LibLegacyTokenSilo._mowAndMigrateMerkleCheck(account, stalkDiff, seedsDiff, proof, seedsVariance);
    }

    /** 
     * @notice Migrates farmer's deposits from old (seasons based) to new silo (stems based).
     * @param account Address of the account to migrate
     *
     * @dev If a user's lastUpdate was set, which means they had deposits in the silo,
     * but they currently have no deposits, then this function can be used to migrate
     * their account to the new silo using less gas.
     */
    function mowAndMigrateNoDeposits(address account) external payable {
        LibLegacyTokenSilo._migrateNoDeposits(account);
    }

    function balanceOfLegacySeeds(address account) external view returns (uint256) {
        return LibLegacyTokenSilo.balanceOfSeeds(account);
    }

    function balanceOfGrownStalkUpToStemsDeployment(address account)
        external
        view
        returns (uint256)
    {
        return LibLegacyTokenSilo.balanceOfGrownStalkUpToStemsDeployment(account);
    }

    /**
     * @dev Locate the `amount` and `bdv` for a user's Deposit in legacy storage.
     * 
     * Silo V2 Deposits are stored within each {Account} as a mapping of:
     *  `address token => uint32 season => { uint128 amount, uint128 bdv }`
     * 
     * Unripe BEAN and Unripe LP are handled independently so that data
     * stored in the legacy Silo V1 format and the new Silo V2 format can
     * be appropriately merged. See {LibUnripeSilo} for more information.
     *
     */
    function getDepositLegacy(
        address account,
        address token,
        uint32 season
    ) external view returns (uint128, uint128) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        if (LibUnripeSilo.isUnripeBean(token)){
            (uint256 amount, uint256 bdv) = LibUnripeSilo.unripeBeanDeposit(account, season);
            return (uint128(amount), uint128(bdv));
        }
        if (LibUnripeSilo.isUnripeLP(token)){
            (uint256 amount, uint256 bdv) = LibUnripeSilo.unripeLPDeposit(account, season);
            return (uint128(amount), uint128(bdv));
        }

        return (
            s.a[account].legacyDeposits[token][season].amount,
            s.a[account].legacyDeposits[token][season].bdv
        );
    }

}

File 3 of 41 : 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;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

File 4 of 41 : 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 5 of 41 : Silo.sol
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./SiloExit.sol";

/**
 * @title Silo
 * @author Publius, Pizzaman1337, Brean
 * @notice Provides utility functions for claiming Silo rewards, including:
 *
 * - Grown Stalk (see "Mow")
 * - Earned Beans, Earned Stalk (see "Plant")
 * - 3CRV earned during a Flood (see "Flood")
 *
 * For backwards compatibility, a Flood is sometimes referred to by its old name
 * "Season of Plenty".
 */
 
contract Silo is SiloExit {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using LibSafeMath128 for uint128;

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

    /**
     * @notice Emitted when the deposit associated with the Earned Beans of
     * `account` are Planted.
     * @param account Owns the Earned Beans
     * @param beans The amount of Earned Beans claimed by `account`.
     */
    event Plant(
        address indexed account,
        uint256 beans
    );

    /**
     * @notice Emitted when 3CRV paid to `account` during a Flood is Claimed.
     * @param account Owns and receives the assets paid during a Flood.
     * @param plenty The amount of 3CRV claimed by `account`. This is the amount
     * that `account` has been paid since their last {ClaimPlenty}.
     * 
     * @dev Flood was previously called a "Season of Plenty". For backwards
     * compatibility, the event has not been changed. For more information on 
     * Flood, see: {Weather.sop}.
     */
    event ClaimPlenty(
        address indexed account,
        uint256 plenty
    );


    /**
     * @notice Emitted when `account` gains or loses Stalk.
     * @param account The account that gained or lost Stalk.
     * @param delta The change in Stalk.
     * @param deltaRoots The change in Roots.
     *   
     * @dev {StalkBalanceChanged} should be emitted anytime a Deposit is added, removed or transferred AND
     * anytime an account Mows Grown Stalk.
     * @dev BIP-24 included a one-time re-emission of {SeedsBalanceChanged} for accounts that had
     * executed a Deposit transfer between the Replant and BIP-24 execution. For more, see:
     * [BIP-24](https://github.com/BeanstalkFarms/Beanstalk-Governance-Proposals/blob/master/bip/bip-24-fungible-bdv-support.md)
     * [Event-24-Event-Emission](https://github.com/BeanstalkFarms/Event-24-Event-Emission)
     */
    event StalkBalanceChanged(
        address indexed account,
        int256 delta,
        int256 deltaRoots
    );

    //////////////////////// INTERNAL: MOW ////////////////////////

    /**
     * @dev Claims the Grown Stalk for `msg.sender`. Requires token address to mow.
     */
    modifier mowSender(address token) {
        LibSilo._mow(msg.sender, token);
        _;
    }

    //////////////////////// INTERNAL: PLANT ////////////////////////

    /**
     * @dev Plants the Plantable BDV of `account` associated with its Earned
     * Beans.
     * 
     * For more info on Planting, see: {SiloFacet-plant}
     */
     
    function _plant(address account) internal returns (uint256 beans, int96 stemTip) {
        // Need to Mow for `account` before we calculate the balance of 
        // Earned Beans.
        
        // per the zero withdraw update, planting is handled differently 
        // depending whether or not the user plants during the vesting period of beanstalk. 
        // during the vesting period, the earned beans are not issued to the user.
        // thus, the roots calculated for a given user is different. 
        // This is handled by the super mow function, which stores the difference in roots.
        LibSilo._mow(account, C.BEAN);
        uint256 accountStalk = s.a[account].s.stalk;

        // Calculate balance of Earned Beans.
        beans = _balanceOfEarnedBeans(account, accountStalk);
        stemTip = LibTokenSilo.stemTipForToken(C.BEAN);
        s.a[account].deltaRoots = 0; // must be 0'd, as calling balanceOfEarnedBeans would give a invalid amount of beans. 
        if (beans == 0) return (0,stemTip);
        
        // Reduce the Silo's supply of Earned Beans.
        // SafeCast unnecessary because beans is <= s.earnedBeans.
        s.earnedBeans = s.earnedBeans.sub(uint128(beans));
        
        // Deposit Earned Beans if there are any. Note that 1 Bean = 1 BDV.
        LibTokenSilo.addDepositToAccount(
            account,
            C.BEAN,
            stemTip,
            beans, // amount
            beans, // bdv
            LibTokenSilo.Transfer.emitTransferSingle
        );
        s.a[account].deltaRoots = 0; // must be 0'd, as calling balanceOfEarnedBeans would give a invalid amount of beans. 

        // Earned Stalk associated with Earned Beans generate more Earned Beans automatically (i.e., auto compounding).
        // Earned Stalk are minted when Earned Beans are minted during Sunrise. See {Sun.sol:rewardToSilo} for details.
        // Similarly, `account` does not receive additional Roots from Earned Stalk during a Plant.
        // The following lines allocate Earned Stalk that has already been minted to `account`.
        // Constant is used here rather than s.ss[BEAN].stalkIssuedPerBdv
        // for gas savings.
        uint256 stalk = beans.mul(C.STALK_PER_BEAN);
        s.a[account].s.stalk = accountStalk.add(stalk);


        emit StalkBalanceChanged(account, int256(stalk), 0);
        emit Plant(account, beans);
    }

    //////////////////////// INTERNAL: SEASON OF PLENTY ////////////////////////

    /**
     * @dev Gas optimization: An account can call `{SiloFacet:claimPlenty}` even
     * if `s.a[account].sop.plenty == 0`. This would emit a ClaimPlenty event
     * with an amount of 0.
     */
    function _claimPlenty(address account) internal {
        // Plenty is earned in the form of 3Crv.
        uint256 plenty = s.a[account].sop.plenty;
        C.threeCrv().safeTransfer(account, plenty);
        delete s.a[account].sop.plenty;

        emit ClaimPlenty(account, plenty);
    }
}

File 6 of 41 : TokenSilo.sol
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma abicoder v2;

import "./Silo.sol";

/**
 * @title TokenSilo
 * @author Publius, Brean, Pizzaman1337
 * @notice This contract contains functions for depositing, withdrawing and 
 * claiming whitelisted Silo tokens.
 *
 *
 * - LibTokenSilo offers `incrementTotalDeposited` and `decrementTotalDeposited`
 *   but these operations are performed directly for withdrawals.
 * - "Removing a Deposit" only removes from the `account`; the total amount
 *   deposited in the Silo is decremented during withdrawal, _after_ a Withdrawal
 *   is created. See "Finish Removal".
 */
contract TokenSilo is Silo {
    using SafeMath for uint256;
    using SafeCast for uint256;
    using LibSafeMath32 for uint32;


    /**
     * @notice Emitted when `account` adds a single Deposit to the Silo.
     *
     * There is no "AddDeposits" event because there is currently no operation in which Beanstalk
     * creates multiple Deposits in different stems:
     *
     *  - `deposit()` always places the user's deposit in the current `_season()`.
     *  - `convert()` collapses multiple deposits into a single Season to prevent loss of Stalk.
     *
     * @param account The account that added a Deposit.
     * @param token Address of the whitelisted ERC20 token that was deposited.
     * @param stem The stem index that this `amount` was added to.
     * @param amount Amount of `token` added to `stem`.
     * @param bdv The BDV associated with `amount` of `token` at the time of Deposit.
     */
    event AddDeposit(
        address indexed account,
        address indexed token,
        int96 stem,
        uint256 amount,
        uint256 bdv
    );

    /**
     * @notice Emitted when `account` removes a single Deposit from the Silo.
     * 
     * Occurs during `withdraw()` and `convert()` operations.
     * 
     * @param account The account that removed a Deposit.
     * @param token Address of the whitelisted ERC20 token that was removed.
     * @param stem The stem that this `amount` was removed from.
     * @param amount Amount of `token` removed from `stem`.
     */
    event RemoveDeposit(
        address indexed account,
        address indexed token,
        int96 stem,
        uint256 amount,
        uint256 bdv
    );

    /**
     * @notice Emitted when `account` removes multiple Deposits from the Silo.
     * Occurs during `withdraw()` and `convert()` operations. 
     * Gas optimization: emit 1 `RemoveDeposits` instead of N `RemoveDeposit` events.
     * 
     * @param account The account that removed Deposits.
     * @param token Address of the whitelisted ERC20 token that was removed.
     * @param stems stems of Deposit to remove from.
     * @param amounts Amounts of `token` to remove from corresponding `stems`.
     * @param amount Sum of `amounts`.
     */
    event RemoveDeposits(
        address indexed account,
        address indexed token,
        int96[] stems,
        uint256[] amounts,
        uint256 amount,
        uint256[] bdvs
    ); //add bdv[] here? in favor of array

    // ERC1155 events
    
    /**
     * @notice Emitted when a Deposit is created, removed, or transferred.
     * 
     * @param operator the address that performed the operation.
     * @param from the address the Deposit is being transferred from.
     * @param to the address the Deposit is being transferred to.
     * @param id the depositID of the Deposit.
     * @param value the amount of the Deposit.
     */
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 value
    );

    /**
     * @notice Emitted when multiple deposits are withdrawn or transferred.
     * 
     * @dev This event is emitted in `convert()`
     * 
     * @param operator the address that performed the operation.
     * @param from the address the Deposit is being transferred from.
     * @param to the address the Deposit is being transferred to.
     * @param ids the depositIDs of the Deposit.
     * @param values the amounts of the Deposit.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );
    
    // LEGACY EVENTS

    /**
     * @notice these events are kept for backwards compatability, 
     * and therefore should not be changed. 
     * placed here in order for the ABI to generate properly. 
     * See {LibLegacyTokenSilo} for implmentation.
     */
    event RemoveWithdrawals(
        address indexed account,
        address indexed token,
        uint32[] seasons,
        uint256 amount
    );
    
    event RemoveWithdrawal(
        address indexed account,
        address indexed token,
        uint32 season,
        uint256 amount
    );

    

    //////////////////////// DEPOSIT ////////////////////////

    /**
     * @dev Handle deposit accounting.
     *
     * - {LibTokenSilo.deposit} calculates BDV, adds a Deposit to `account`, and
     *   increments the total amount Deposited.
     * - {LibSilo.mintStalk} mints the Stalk associated with
     *   the Deposit.
     * 
     * This step should enforce that new Deposits are placed into the current 
     * `LibTokenSilo.stemTipForToken(token)`.
     */
    function _deposit(
        address account,
        address token,
        uint256 amount
    ) internal returns (uint256 stalk, int96 stem) {
        stalk = LibTokenSilo.deposit(
            account,
            token,
            stem = LibTokenSilo.stemTipForToken(token),
            amount
        );
        LibSilo.mintStalk(account, stalk);
    }

    //////////////////////// WITHDRAW ////////////////////////

    /**
     * @notice Handles withdraw accounting.
     *
     * - {LibSilo._removeDepositFromAccount} calculates the stalk
     * assoicated with a given deposit, and removes the deposit from the account.
     * emits `RemoveDeposit` and `TransferSingle` events. 
     * 
     * - {_withdraw} updates the total value deposited in the silo, and burns 
     * the stalk assoicated with the deposits.
     * 
     */
    function _withdrawDeposit(
        address account,
        address token,
        int96 stem,
        uint256 amount
    ) internal {
        // Remove the Deposit from `account`.
        (uint256 stalkRemoved, uint256 bdvRemoved) = LibSilo._removeDepositFromAccount(
            account,
            token,
            stem,
            amount,
            LibTokenSilo.Transfer.emitTransferSingle
        );
        
        _withdraw(
            account,
            address(token),
            amount,
            bdvRemoved,
            stalkRemoved
        );
    }

    /**
     * @notice Handles withdraw accounting for multiple deposits.
     *
     * - {LibSilo._removeDepositsFromAccount} removes the deposits from the account,
     * and returns the total tokens, stalk, and bdv removed from the account.
     * 
     * - {_withdraw} updates the total value deposited in the silo, and burns 
     * the stalk assoicated with the deposits.
     * 
     */
    function _withdrawDeposits(
        address account,
        address token,
        int96[] calldata stems,
        uint256[] calldata amounts
    ) internal returns (uint256) {
        require(
            stems.length == amounts.length,
            "Silo: Crates, amounts are diff lengths."
        );

        LibSilo.AssetsRemoved memory ar = LibSilo._removeDepositsFromAccount(
            account,
            token,
            stems,
            amounts
        );

        _withdraw(
            account,
            token,
            ar.tokensRemoved,
            ar.bdvRemoved,
            ar.stalkRemoved
        );

        // we return the total tokens removed from the deposits,
        // to be used in {SiloFacet.withdrawDeposits}.
        return ar.tokensRemoved;
    }

    /**
     * @dev internal helper function for withdraw accounting.
     */
    function _withdraw(
        address account,
        address token,
        uint256 amount,
        uint256 bdv,
        uint256 stalk
    ) private {
        LibTokenSilo.decrementTotalDeposited(token, amount, bdv); // Decrement total Deposited in the silo.
        LibSilo.burnStalk(account, stalk); // Burn stalk and roots associated with the stalk.
    }

    //////////////////////// TRANSFER ////////////////////////

    /**
     * @notice Intenral transfer logic accounting. 
     * 
     * @dev Removes `amount` of a single Deposit from `sender` and transfers
     * it to `recipient`. No Stalk are burned, and the total amount of
     * Deposited `token` in the Silo doesn't change. 
     */
    function _transferDeposit(
        address sender,
        address recipient,
        address token,
        int96 stem,
        uint256 amount
    ) internal returns (uint256) {
        (uint256 stalk, uint256 bdv) = LibSilo._removeDepositFromAccount(
            sender,
            token,
            stem,
            amount,
            LibTokenSilo.Transfer.noEmitTransferSingle
        );
        LibTokenSilo.addDepositToAccount(
            recipient, 
            token, 
            stem, 
            amount, 
            bdv,
            LibTokenSilo.Transfer.noEmitTransferSingle
        );
        LibSilo.transferStalk(sender, recipient, stalk);

        /** 
         * the current beanstalk system uses {AddDeposit}
         * and {RemoveDeposit} events to represent a transfer.
         * However, the ERC1155 standard has a dedicated {TransferSingle} event,
         * which is used here.
         */
        emit TransferSingle(
            msg.sender, 
            sender, 
            recipient, 
            LibBytes.packAddressAndStem(token, stem),
            amount
        );

        return bdv;
    }

    /**
     * @notice Intenral transfer logic accounting for multiple deposits.
     * 
     * @dev Removes `amounts` of multiple Deposits from `sender` and transfers
     * them to `recipient`. No Stalk are burned, and the total amount of
     * Deposited `token` in the Silo doesn't change. 
     */
    function _transferDeposits(
        address sender,
        address recipient,
        address token,
        int96[] calldata stems,
        uint256[] calldata amounts
    ) internal returns (uint256[] memory) {
        require(
            stems.length == amounts.length,
            "Silo: Crates, amounts are diff lengths."
        );

        LibSilo.AssetsRemoved memory ar;
        uint256[] memory bdvs = new uint256[](stems.length);
        uint256[] memory removedDepositIDs = new uint256[](stems.length);

        // Similar to {removeDepositsFromAccount}, however the Deposit is also 
        // added to the recipient's account during each iteration.
        for (uint256 i; i < stems.length; ++i) {
            uint256 depositID = uint256(LibBytes.packAddressAndStem(token, stems[i]));
            uint256 crateBdv = LibTokenSilo.removeDepositFromAccount(
                sender,
                token,
                stems[i],
                amounts[i]
            );
            LibTokenSilo.addDepositToAccount(
                recipient,
                token,
                stems[i],
                amounts[i],
                crateBdv,
                LibTokenSilo.Transfer.noEmitTransferSingle
            );
            ar.bdvRemoved = ar.bdvRemoved.add(crateBdv);
            ar.tokensRemoved = ar.tokensRemoved.add(amounts[i]);
            ar.stalkRemoved = ar.stalkRemoved.add(
                LibSilo.stalkReward(
                    stems[i],
                    LibTokenSilo.stemTipForToken(token),
                    crateBdv.toUint128()
                )
            );
            bdvs[i] = crateBdv;
            removedDepositIDs[i] = depositID;

        }

        ar.stalkRemoved = ar.stalkRemoved.add(
            ar.bdvRemoved.mul(s.ss[token].stalkIssuedPerBdv)
        );

        /** 
         *  The current beanstalk system uses a mix of {AddDeposit}
         *  and {RemoveDeposits} events to represent a batch transfer.
         *  However, the ERC1155 standard has a dedicated {batchTransfer} event,
         *  which is used here.
         */
        emit LibSilo.TransferBatch(msg.sender, sender, recipient, removedDepositIDs, amounts);
        emit RemoveDeposits(sender, token, stems, amounts, ar.tokensRemoved, bdvs);

        LibSilo.transferStalk(
            sender,
            recipient,
            ar.stalkRemoved
        );

        return bdvs;
    }

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

    /**
     * @notice Find the amount and BDV of `token` that `account` has Deposited in stem index `stem`.
     * 
     * Returns a deposit tuple `(uint256 amount, uint256 bdv)`.
     *
     * @return amount The number of tokens contained in this Deposit.
     * @return bdv The BDV associated with this Deposit.
     */
    function getDeposit(
        address account,
        address token,
        int96 stem
    ) external view returns (uint256, uint256) {
        return LibTokenSilo.getDeposit(account, token, stem);
    }

    /**
     * @notice Get the total amount of `token` currently Deposited in the Silo across all users.
     */
    function getTotalDeposited(address token) external view returns (uint256) {
        return s.siloBalances[token].deposited;
    }

    /**
     * @notice Get the total bdv of `token` currently Deposited in the Silo across all users.
     */
    function getTotalDepositedBdv(address token) external view returns (uint256) {
        return s.siloBalances[token].depositedBdv;
    }

    /**
     * @notice Get the Storage.SiloSettings for a whitelisted Silo token.
     *
     * Contains:
     *  - the BDV function selector
     *  - Stalk per BDV
     *  - stalkEarnedPerSeason
     *  - milestoneSeason
     *  - lastStem
     */
    function tokenSettings(address token)
        external
        view
        returns (Storage.SiloSettings memory)
    {
        return s.ss[token];
    }

    //////////////////////// ERC1155 ////////////////////////

    /**
     * @notice returns the amount of tokens in a Deposit.
     * 
     * @dev see {getDeposit} for both the bdv and amount.
     */
    function balanceOf(
        address account, 
        uint256 depositId
    ) external view returns (uint256 amount) {
        return s.a[account].deposits[depositId].amount;
    }

    /**
     * @notice returns an array of amounts corresponding to Deposits.
     */
    function balanceOfBatch(
        address[] calldata accounts, 
        uint256[] calldata depositIds
    ) external view returns (uint256[] memory) {
        require(
            accounts.length == depositIds.length, 
            "ERC1155: ids and amounts length mismatch"
        );
        uint256[] memory balances = new uint256[](accounts.length);
        for (uint256 i = 0; i < accounts.length; i++) {
            balances[i] = s.a[accounts[i]].deposits[depositIds[i]].amount;
        }
        return balances;
    }

    /**
     * @notice outputs the depositID given an token address and stem.
     */
    function getDepositId(
        address token, 
        int96 stem
    ) external pure returns (uint256) {
        return LibBytes.packAddressAndStem(token, stem);
    }
}

File 7 of 41 : LibSilo.sol
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma abicoder v2;

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

/**
 * @title LibSilo
 * @author Publius
 * @notice Contains functions for minting, burning, and transferring of
 * Stalk and Roots within the Silo.
 *
 * @dev Here, we refer to "minting" as the combination of
 * increasing the total balance of Stalk/Roots, as well as allocating
 * them to a particular account. However, in other places throughout Beanstalk
 * (like during the Sunrise), Beanstalk's total balance of Stalk increases
 * without allocating to a particular account. One example is {Sun-rewardToSilo}
 * which increases `s.s.stalk` but does not allocate it to any account. The
 * allocation occurs during `{SiloFacet-plant}`. Does this change how we should
 * call "minting"?
 *
 * In the ERC20 context, "minting" increases the supply of a token and allocates
 * the new tokens to an account in one action. I've adjusted the comments below
 * to use "mint" in the same sense.
 */
library LibSilo {
    using SafeMath for uint256;
    using LibSafeMath128 for uint128;
    using LibSafeMathSigned96 for int96;
    using LibPRBMath for uint256;
    using SafeCast for uint256;
    
    // The `VESTING_PERIOD` is the number of blocks that must pass before
    // a farmer is credited with their earned beans issued that season. 
    uint256 internal constant VESTING_PERIOD = 10;

    //////////////////////// EVENTS ////////////////////////    
     
    /**
     * @notice Emitted when `account` gains or loses Stalk.
     * @param account The account that gained or lost Stalk.
     * @param delta The change in Stalk.
     * @param deltaRoots The change in Roots.
     *   
     * @dev Should be emitted anytime a Deposit is added, removed or transferred
     * AND anytime an account Mows Grown Stalk.
     * 
     * BIP-24 included a one-time re-emission of {StalkBalanceChanged} for
     * accounts that had executed a Deposit transfer between the Replant and
     * BIP-24 execution. For more, see:
     *
     * [BIP-24](https://bean.money/bip-24)
     * [Event-Emission](https://github.com/BeanstalkFarms/BIP-24-Event-Emission)
     */
    event StalkBalanceChanged(
        address indexed account,
        int256 delta,
        int256 deltaRoots
    );

    /**
     * @notice Emitted when a deposit is removed from the silo.
     * 
     * @param account The account assoicated with the removed deposit.
     * @param token The token address of the removed deposit.
     * @param stem The stem of the removed deposit.
     * @param amount The amount of "token" removed from an deposit.
     * @param bdv The instanteous bdv removed from the deposit.
     */
    event RemoveDeposit(
        address indexed account,
        address indexed token,
        int96 stem,
        uint256 amount,
        uint256 bdv
    );

    /**
     * @notice Emitted when multiple deposits are removed from the silo.
     * 
     * @param account The account assoicated with the removed deposit.
     * @param token The token address of the removed deposit.
     * @param stems A list of stems of the removed deposits.
     * @param amounts A list of amounts removed from the deposits.
     * @param amount the total summation of the amount removed.
     * @param bdvs A list of bdvs removed from the deposits.
     */
    event RemoveDeposits(
        address indexed account,
        address indexed token,
        int96[] stems,
        uint256[] amounts,
        uint256 amount,
        uint256[] bdvs
    );

    struct AssetsRemoved {
        uint256 tokensRemoved;
        uint256 stalkRemoved;
        uint256 bdvRemoved;
    }

    /**
     * @notice Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator, 
        address indexed from, 
        address indexed to, 
        uint256[] ids, 
        uint256[] values
    );

    //////////////////////// MINT ////////////////////////

    /**
     * @dev Mints Stalk and Roots to `account`.
     *
     * `roots` are an underlying accounting variable that is used to track
     * how many earned beans a user has. 
     * 
     * When a farmer's state is updated, the ratio should hold:
     * 
     *  Total Roots     User Roots
     * ------------- = ------------
     *  Total Stalk     User Stalk
     *  
     * @param account the address to mint Stalk and Roots to
     * @param stalk the amount of stalk to mint
     */
    function mintStalk(address account, uint256 stalk) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();

        // Calculate the amount of Roots for the given amount of Stalk.
        uint256 roots;
        if (s.s.roots == 0) {
            roots = uint256(stalk.mul(C.getRootsBase()));
        } else {
            roots = s.s.roots.mul(stalk).div(s.s.stalk);
        }
        
        
        // increment user and total stalk
        s.s.stalk = s.s.stalk.add(stalk);
        s.a[account].s.stalk = s.a[account].s.stalk.add(stalk);

        // increment user and total roots
        s.s.roots = s.s.roots.add(roots);
        s.a[account].roots = s.a[account].roots.add(roots);


        emit StalkBalanceChanged(account, int256(stalk), int256(roots));
    }


    /**
     * @dev mints grownStalk to `account`.
     * 
     * per the zero-withdraw update, if a user plants during the vesting period (see constant),
     * the earned beans of the current season is deferred until the non vesting period.
     * However, this causes a slight mismatch in the amount of roots to properly allocate to the user.
     * 
     * The formula for calculating the roots is:
     * GainedRoots = TotalRoots * GainedStalk / TotalStalk.
     * 
     * Roots are utilized in {SiloExit.balanceOfEarnedBeans} to calculate the earned beans as such: 
     * EarnedBeans = (TotalStalk * userRoots / TotalRoots) - userStalk  
     * 
     * Because TotalStalk increments when there are new beans issued (at sunrise), 
     * the amount of roots issued without the earned beans are:
     * GainedRoots = TotalRoots * GainedStalk / (TotalStalk - NewEarnedStalk)
     * 
     * since newEarnedStalk is always equal or greater than 0, the gained roots calculated without the earned beans
     * will always be equal or larger than the gained roots calculated with the earned beans.
     * 
     * @param account the address to mint Stalk and Roots to
     * @param stalk the amount of stalk to mint
     */
    function mintGrownStalk(address account, uint256 stalk) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();

        uint256 roots;
        if (s.s.roots == 0) {
            roots = stalk.mul(C.getRootsBase());
        } else {
            roots = s.s.roots.mul(stalk).div(s.s.stalk);
            if (inVestingPeriod()) {
                // Safe Math is unnecessary for because total Stalk > new Earned Stalk
                uint256 rootsWithoutEarned = s.s.roots.add(s.vestingPeriodRoots).mul(stalk).div(s.s.stalk - s.newEarnedStalk);
                // Safe Math is unnecessary for because rootsWithoutEarned >= roots
                uint128 deltaRoots = (rootsWithoutEarned - roots).toUint128();
                s.vestingPeriodRoots = s.vestingPeriodRoots.add(deltaRoots);
                s.a[account].deltaRoots = deltaRoots;
            }
        }

        // increment user and total stalk
        s.s.stalk = s.s.stalk.add(stalk);
        s.a[account].s.stalk = s.a[account].s.stalk.add(stalk);

        // increment user and total roots
        s.s.roots = s.s.roots.add(roots);
        s.a[account].roots = s.a[account].roots.add(roots);

        emit StalkBalanceChanged(account, int256(stalk), int256(roots));
    }

    //////////////////////// BURN ////////////////////////

    /**
     * @dev Burns Stalk and Roots from `account`.
     *
     * if the user withdraws in the vesting period, 
     * they forfeit their earned beans for that season, 
     * distrubuted to the other users.
     */
    function burnStalk(address account, uint256 stalk) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (stalk == 0) return;
       
        uint256 roots;
        // Calculate the amount of Roots for the given amount of Stalk.
        // We round up as it prevents an account having roots but no stalk.
        
        // if the user withdraws in the vesting period, they forfeit their earned beans for that season
        // this is distributed to the other users.
        if(inVestingPeriod()){
            roots = s.s.roots.mulDiv(
                stalk,
                s.s.stalk-s.newEarnedStalk,
                LibPRBMath.Rounding.Up
            );
            // cast to uint256 to prevent overflow
            uint256 deltaRootsRemoved = uint256(s.a[account].deltaRoots)
                .mul(stalk)
                .div(s.a[account].s.stalk);
            s.a[account].deltaRoots = s.a[account].deltaRoots.sub(deltaRootsRemoved.toUint128());
        } else {
            roots = s.s.roots.mulDiv(
            stalk,
            s.s.stalk,
            LibPRBMath.Rounding.Up);
        }

        if (roots > s.a[account].roots) roots = s.a[account].roots;

        // Decrease supply of Stalk; Remove Stalk from the balance of `account`
        s.s.stalk = s.s.stalk.sub(stalk);
        s.a[account].s.stalk = s.a[account].s.stalk.sub(stalk);

        // Decrease supply of Roots; Remove Roots from the balance of `account`
        s.s.roots = s.s.roots.sub(roots);
        s.a[account].roots = s.a[account].roots.sub(roots);
        
        // Oversaturated was previously referred to as Raining and thus
        // code references mentioning Rain really refer to Oversaturation
        // If Beanstalk is Oversaturated, subtract Roots from both the
        // account's and Beanstalk's Oversaturated Roots balances.
        // For more info on Oversaturation, See {Weather.handleRain}
        if (s.season.raining) {
            s.r.roots = s.r.roots.sub(roots);
            s.a[account].sop.roots = s.a[account].roots;
        }

        emit StalkBalanceChanged(account, -int256(stalk), -int256(roots));
    }

    //////////////////////// TRANSFER ////////////////////////

    /**
     * @notice Decrements the Stalk and Roots of `sender` and increments the Stalk
     * and Roots of `recipient` by the same amount.
     * 
     * If the transfer is done during the vesting period, the earned beans are still
     * defered until after the vesting period has elapsed. 
     * @dev There may be cases where more than the earned beans 
     * of the current season is vested, but can be claimed after the v.e has ended.
     * We accept this inefficency due to 
     * 1) the short vesting period.
     * 2) math complexity/gas costs needed to implement a correct solution.
     * 3) security risks.
     */
    function transferStalk(
        address sender,
        address recipient,
        uint256 stalk
    ) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 roots;
        if(inVestingPeriod()){
            // transferring all stalk means that the earned beans is transferred.
            // deltaRoots cannot be transferred as it is calculated on an account basis. 
            if(stalk == s.a[sender].s.stalk){
                s.a[sender].deltaRoots = 0;
            } else {
                // partial transfer
                uint256 deltaRootsRemoved = uint256(s.a[sender].deltaRoots)
                    .mul(stalk)
                    .div(s.a[sender].s.stalk);
                s.a[sender].deltaRoots = s.a[sender].deltaRoots.sub(deltaRootsRemoved.toUint128());
            }
            roots = stalk == s.a[sender].s.stalk
                ? s.a[sender].roots
                : s.s.roots.sub(1).mul(stalk).div(s.s.stalk - s.newEarnedStalk).add(1);
        } else {
            roots = stalk == s.a[sender].s.stalk
            ? s.a[sender].roots
            : s.s.roots.sub(1).mul(stalk).div(s.s.stalk).add(1);
        }

        // Subtract Stalk and Roots from the 'sender' balance.        
        s.a[sender].s.stalk = s.a[sender].s.stalk.sub(stalk);
        s.a[sender].roots = s.a[sender].roots.sub(roots);
        emit StalkBalanceChanged(sender, -int256(stalk), -int256(roots));

        // Add Stalk and Roots to the 'recipient' balance.
        s.a[recipient].s.stalk = s.a[recipient].s.stalk.add(stalk);
        s.a[recipient].roots = s.a[recipient].roots.add(roots);
        emit StalkBalanceChanged(recipient, int256(stalk), int256(roots));
    }

    /**
     * @dev Claims the Grown Stalk for `account` and applies it to their Stalk
     * balance. Also handles Season of Plenty related rain.
     *
     * This is why `_mow()` must be called before any actions that change Seeds,
     * including:
     *  - {SiloFacet-deposit}
     *  - {SiloFacet-withdrawDeposit}
     *  - {SiloFacet-withdrawDeposits}
     *  - {_plant}
     *  - {SiloFacet-transferDeposit(s)}
     */
   function _mow(address account, address token) internal {

        require(!migrationNeeded(account), "Silo: Migration needed");

        AppStorage storage s = LibAppStorage.diamondStorage();
        //sop stuff only needs to be updated once per season
        //if it started raininga nd it's still raining, or there was a sop
        if (s.season.rainStart > s.season.stemStartSeason) {
            uint32 lastUpdate = _lastUpdate(account);
            if (lastUpdate <= s.season.rainStart && lastUpdate <= s.season.current) {
                // Increments `plenty` for `account` if a Flood has occured.
                // Saves Rain Roots for `account` if it is Raining.
                handleRainAndSops(account, lastUpdate);

                // Reset timer so that Grown Stalk for a particular Season can only be 
                // claimed one time. 
                s.a[account].lastUpdate = s.season.current;
            }
        }
        
        // Calculate the amount of Grown Stalk claimable by `account`.
        // Increase the account's balance of Stalk and Roots.
        __mow(account, token);

        // was hoping to not have to update lastUpdate, but if you don't, then it's 0 for new depositors, this messes up mow and migrate in unit tests, maybe better to just set this manually for tests?
        // anyone that would have done any deposit has to go through mowSender which would have init'd it above zero in the pre-migration days
        s.a[account].lastUpdate = s.season.current;
    }

    /**
     * @dev Updates the mowStatus for the given account and token, 
     * and mints Grown Stalk for the given account and token.
     */
    function __mow(address account, address token) private {
        AppStorage storage s = LibAppStorage.diamondStorage();

        int96 _stemTip = LibTokenSilo.stemTipForToken(token);
        int96 _lastStem =  s.a[account].mowStatuses[token].lastStem;
        uint128 _bdv = s.a[account].mowStatuses[token].bdv;
        
        // if 
        // 1: account has no bdv (new token deposit)
        // 2: the lastStem is the same as the stemTip (implying that a user has mowed),
        // then skip calculations to save gas.
        if (_bdv > 0) {
            if (_lastStem == _stemTip) {
                return;
            }

            mintGrownStalk(
                account,
                _balanceOfGrownStalk(
                    _lastStem,
                    _stemTip,
                    _bdv
                )
            );
        }

        // If this `account` has no BDV, skip to save gas. Still need to update lastStem 
        // (happen on initial deposit, since mow is called before any deposit)
        s.a[account].mowStatuses[token].lastStem = _stemTip;
        return;
    }

    /**
     * @notice returns the last season an account interacted with the silo.
     */
    function _lastUpdate(address account) internal view returns (uint32) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.a[account].lastUpdate;
    }

    /**
     * @dev internal logic to handle when beanstalk is raining.
     */
    function handleRainAndSops(address account, uint32 lastUpdate) private {
        AppStorage storage s = LibAppStorage.diamondStorage();
        // If no roots, reset Sop counters variables
        if (s.a[account].roots == 0) {
            s.a[account].lastSop = s.season.rainStart;
            s.a[account].lastRain = 0;
            return;
        }
        // If a Sop has occured since last update, calculate rewards and set last Sop.
        if (s.season.lastSopSeason > lastUpdate) {
            s.a[account].sop.plenty = balanceOfPlenty(account);
            s.a[account].lastSop = s.season.lastSop;
        }
        if (s.season.raining) {
            // If rain started after update, set account variables to track rain.
            if (s.season.rainStart > lastUpdate) {
                s.a[account].lastRain = s.season.rainStart;
                s.a[account].sop.roots = s.a[account].roots;
            }
            // If there has been a Sop since rain started,
            // save plentyPerRoot in case another SOP happens during rain.
            if (s.season.lastSop == s.season.rainStart) {
                s.a[account].sop.plentyPerRoot = s.sops[s.season.lastSop];
            }
        } else if (s.a[account].lastRain > 0) {
            // Reset Last Rain if not raining.
            s.a[account].lastRain = 0;
        }
    }

    /**
     * @dev returns the balance of amount of grown stalk based on stems.
     * @param lastStem the stem assoicated with the last mow
     * @param latestStem the current stem for a given token
     * @param bdv the bdv used to calculate grown stalk
     */
    function _balanceOfGrownStalk(
        int96 lastStem,
        int96 latestStem,
        uint128 bdv
    ) internal pure returns (uint256)
    {
        return stalkReward(lastStem, latestStem, bdv);
    } 

    /**
     * @dev returns the amount of `plenty` an account has.
     */
    function balanceOfPlenty(address account)
        internal
        view
        returns (uint256 plenty)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        Account.State storage a = s.a[account];
        plenty = a.sop.plenty;
        uint256 previousPPR;

        // If lastRain > 0, then check if SOP occured during the rain period.
        if (s.a[account].lastRain > 0) {
            // if the last processed SOP = the lastRain processed season,
            // then we use the stored roots to get the delta.
            if (a.lastSop == a.lastRain) previousPPR = a.sop.plentyPerRoot;
            else previousPPR = s.sops[a.lastSop];
            uint256 lastRainPPR = s.sops[s.a[account].lastRain];

            // If there has been a SOP duing the rain sesssion since last update, process SOP.
            if (lastRainPPR > previousPPR) {
                uint256 plentyPerRoot = lastRainPPR - previousPPR;
                previousPPR = lastRainPPR;
                plenty = plenty.add(
                    plentyPerRoot.mul(s.a[account].sop.roots).div(
                        C.SOP_PRECISION
                    )
                );
            }
        } else {
            // If it was not raining, just use the PPR at previous SOP.
            previousPPR = s.sops[s.a[account].lastSop];
        }

        // Handle and SOPs that started + ended before after last Silo update.
        if (s.season.lastSop > _lastUpdate(account)) {
            uint256 plentyPerRoot = s.sops[s.season.lastSop].sub(previousPPR);
            plenty = plenty.add(
                plentyPerRoot.mul(s.a[account].roots).div(
                    C.SOP_PRECISION
                )
            );
        }
    }

    //////////////////////// REMOVE ////////////////////////

    /**
     * @dev Removes from a single Deposit, emits the RemoveDeposit event,
     * and returns the Stalk/BDV that were removed.
     *
     * Used in:
     * - {TokenSilo:_withdrawDeposit}
     * - {TokenSilo:_transferDeposit}
     */
    function _removeDepositFromAccount(
        address account,
        address token,
        int96 stem,
        uint256 amount,
        LibTokenSilo.Transfer transferType
    )
        internal
        returns (
            uint256 stalkRemoved,
            uint256 bdvRemoved
        )
    {
        AppStorage storage s = LibAppStorage.diamondStorage();

        bdvRemoved = LibTokenSilo.removeDepositFromAccount(account, token, stem, amount);

        //need to get amount of stalk earned by this deposit (index of now minus index of when deposited)
        stalkRemoved = bdvRemoved.mul(s.ss[token].stalkIssuedPerBdv).add(
            stalkReward(
                stem, //this is the index of when it was deposited
                LibTokenSilo.stemTipForToken(token), //this is latest for this token
                bdvRemoved.toUint128()
            )
        );
        /** 
         *  {_removeDepositFromAccount} is used for both withdrawing and transferring deposits.
         *  In the case of a withdraw, only the {TransferSingle} Event needs to be emitted.
         *  In the case of a transfer, a different {TransferSingle}/{TransferBatch} 
         *  Event is emitted in {TokenSilo._transferDeposit(s)}, 
         *  and thus, this event is ommited.
         */
        if(transferType == LibTokenSilo.Transfer.emitTransferSingle){
            // "removing" a deposit is equivalent to "burning" an ERC1155 token.
            emit LibTokenSilo.TransferSingle(
                msg.sender, // operator
                account, // from
                address(0), // to
                LibBytes.packAddressAndStem(token, stem), // depositid
                amount // token amount
            );
        }
        emit RemoveDeposit(account, token, stem, amount, bdvRemoved);
    }

    /**
     * @dev Removes from multiple Deposits, emits the RemoveDeposits
     * event, and returns the Stalk/BDV that were removed.
     * 
     * Used in:
     * - {TokenSilo:_withdrawDeposits}
     * - {SiloFacet:enrootDeposits}
     */
    function _removeDepositsFromAccount(
        address account,
        address token,
        int96[] calldata stems,
        uint256[] calldata amounts
    ) internal returns (AssetsRemoved memory ar) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        //make bdv array and add here?
        uint256[] memory bdvsRemoved = new uint256[](stems.length);
        uint256[] memory removedDepositIDs = new uint256[](stems.length);

        for (uint256 i; i < stems.length; ++i) {
            uint256 crateBdv = LibTokenSilo.removeDepositFromAccount(
                account,
                token,
                stems[i],
                amounts[i]
            );
            bdvsRemoved[i] = crateBdv;
            removedDepositIDs[i] = LibBytes.packAddressAndStem(token, stems[i]);
            ar.bdvRemoved = ar.bdvRemoved.add(crateBdv);
            ar.tokensRemoved = ar.tokensRemoved.add(amounts[i]);

            ar.stalkRemoved = ar.stalkRemoved.add(
                stalkReward(
                    stems[i],
                    LibTokenSilo.stemTipForToken(token),
                    crateBdv.toUint128()
                )
            );

        }

        ar.stalkRemoved = ar.stalkRemoved.add(
            ar.bdvRemoved.mul(s.ss[token].stalkIssuedPerBdv)
        );

        // "removing" deposits is equivalent to "burning" a batch of ERC1155 tokens.
        emit TransferBatch(msg.sender, account, address(0), removedDepositIDs, amounts);
        emit RemoveDeposits(account, token, stems, amounts, ar.tokensRemoved, bdvsRemoved);
    }

    
    //////////////////////// UTILITIES ////////////////////////

    /**
     * @dev Calculates the Stalk reward based on the start and end
     * stems, and the amount of BDV deposited. Stems represent the
     * amount of grown stalk per BDV, so the difference between the 
     * start index and end index (stem) multiplied by the amount of
     * bdv deposited will give the amount of stalk earned.
     * formula: stalk = bdv * (ΔstalkPerBdv)
     */
    function stalkReward(int96 startStem, int96 endStem, uint128 bdv) //are the types what we want here?
        internal
        pure
        returns (uint256)
    {
        int96 reward = endStem.sub(startStem).mul(int96(bdv));
        
        return uint128(reward);
    }

    /**
     * @dev check whether beanstalk is in the vesting period.
     */
    function inVestingPeriod() internal view returns (bool) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return block.number - s.season.sunriseBlock <= VESTING_PERIOD;
    }

    /**
     * @dev check whether the account needs to be migrated.
     */
    function migrationNeeded(address account) internal view returns (bool) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.a[account].lastUpdate > 0 && s.a[account].lastUpdate < s.season.stemStartSeason;
    }
}

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

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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


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


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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

        // BDV functions accept one argument: `uint256 amount`
        bytes memory callData = abi.encodeWithSelector(
            s.ss[token].selector,
            amount
        );

        (bool success, bytes memory data) = address(this).staticcall(
            callData
        );

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

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

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

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

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

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

        grownStalk = deltaStemTip.mul(bdv);
    }

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

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

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


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

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

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

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

File 9 of 41 : LibLegacyTokenSilo.sol
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

/**
 * @title LibLegacyTokenSilo
 * @author Publius, pizzaman1337
 * @notice Contains legacy silo logic, used for migrating to the
 * new SiloV3 stems-based system, and for claiming in-flight withdrawals
 * from the old silo system.
 * 
 * After all Silos are migrated to V3 and all deposits are claimed, this 
 * library should no longer be necessary.
 */
library LibLegacyTokenSilo {
    using SafeMath for uint256;
    using SafeCast for uint256;
    using LibSafeMathSigned128 for int128;
    using LibSafeMathSigned96 for int96;
    using LibSafeMath32 for uint32;
    using LibSafeMath128 for uint128;

    //to get the new root, run `node scripts/silov3-merkle/stems_merkle.js`
    bytes32 constant DISCREPANCY_MERKLE_ROOT = 0xa84dc86252c556839dff46b290f0c401088a65584aa38a163b6b3f7dd7a5b0e8;
    uint32 constant ENROOT_FIX_SEASON = 12793; //season in which enroot ebip-8 fix was deployed


    //this is the legacy seasons-based remove deposits event, emitted on migration
    event RemoveDeposit(
        address indexed account,
        address indexed token,
        uint32 season,
        uint256 amount
    );

    //legacy seeds balanced changed event, used upon migration
    event SeedsBalanceChanged(
        address indexed account,
        int256 delta
    );

    //legacy stalk balanced changed event, used upon migration
    event StalkBalanceChanged(
        address indexed account,
        int256 delta,
        int256 deltaRoots
    );

    /// @dev these events are grandfathered for claiming deposits. 
    event RemoveWithdrawals(
        address indexed account,
        address indexed token,
        uint32[] seasons,
        uint256 amount
    );
    event RemoveWithdrawal(
        address indexed account,
        address indexed token,
        uint32 season,
        uint256 amount
    );

    struct MigrateData {
        uint128 totalSeeds;
        uint128 totalGrownStalk;
    }

    struct PerDepositData {
        uint32 season;
        uint128 amount;
        uint128 grownStalk;
    }

    struct PerTokenData {
        address token;
        int96 stemTip;
    }

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

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

        uint256 crateAmount;
        (crateAmount, crateBDV) = (
            s.a[account].legacyDeposits[token][season].amount,
            s.a[account].legacyDeposits[token][season].bdv
        );

        // If amount to remove is greater than the amount in the Deposit, migrate legacy Deposit to new Deposit
        if (amount > crateAmount) {
            // If Unripe Deposit, fetch whole Deposit balance and delete legacy deposit references.
            if (LibUnripeSilo.isUnripeBean(token)) {
                (crateAmount, crateBDV) = LibUnripeSilo.unripeBeanDeposit(account, season);
                LibUnripeSilo.removeLegacyUnripeBeanDeposit(account, season);
            } else if (LibUnripeSilo.isUnripeLP(token)) {
                (crateAmount, crateBDV) = LibUnripeSilo.unripeLPDeposit(account, season);
                LibUnripeSilo.removeLegacyUnripeLPDeposit(account, season);
            }
            require(crateAmount >= amount, "Silo: Crate balance too low.");
        }

        // Partial Withdraw
        if (amount < crateAmount) {
            uint256 removedBDV = amount.mul(crateBDV).div(crateAmount);
            uint256 updatedBDV = crateBDV.sub(removedBDV);
            uint256 updatedAmount = crateAmount.sub(amount);
            require(
                updatedBDV <= uint128(-1) && updatedAmount <= uint128(-1),
                "Silo: uint128 overflow."
            );

            s.a[account].legacyDeposits[token][season].amount = uint128(
                updatedAmount
            );
            s.a[account].legacyDeposits[token][season].bdv = uint128(
                updatedBDV
            );

            return removedBDV;
        }

        // Full Remove
        delete s.a[account].legacyDeposits[token][season];
    }

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


    /**
     * @notice Returns the balance of Grown Stalk for `account` up until the
     * Stems deployment season.
     * @dev The balance of Grown Stalk for an account can be calculated as:
     *
     * ```
     * elapsedSeasons = currentSeason - lastUpdatedSeason
     * grownStalk = balanceOfSeeds * elapsedSeasons
     * ```
     */
    function balanceOfGrownStalkUpToStemsDeployment(address account)
        internal
        view
        returns (uint256)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();

        uint32 stemStartSeason = uint32(s.season.stemStartSeason);
        uint32 lastUpdate = s.a[account].lastUpdate;

        if (lastUpdate > stemStartSeason) return 0; 
        return
            stalkReward(
                s.a[account].s.seeds,
                stemStartSeason.sub(lastUpdate)
            );
    }

    /**
     * @param seeds The number of Seeds held.
     * @param seasons The number of Seasons that have elapsed.
     *
     * @dev Calculates the Stalk that has Grown from a given number of Seeds
     * over a given number of Seasons.
     *
     * Each Seed yields 1E-4 (0.0001, or 1 / 10_000) Stalk per Season.
     *
     * Seasons is measured to 0 decimals. There are no fractional Seasons.
     * Seeds are measured to 6 decimals.
     * Stalk is measured to 10 decimals.
     * 
     * Example:
     *  - `seeds = 1E6` (1 Seed)
     *  - `seasons = 1` (1 Season)
     *  - The result is `1E6 * 1 = 1E6`. Since Stalk is measured to 10 decimals,
     *    this is `1E6/1E10 = 1E-4` Stalk.
     */
    function stalkReward(uint256 seeds, uint32 seasons)
        internal
        pure
        returns (uint256)
    {
        return seeds.mul(seasons);
    }

    /** 
     * @notice Calculates stem based on input season
     * @param seedsPerBdv Seeds per bdv for the token you want to find the corresponding stem for
     * @param season The season you want to find the corresponding stem for
     *
     * @dev Used by the mowAndMigrate function to convert seasons to stems, to know which
     * stem to deposit in for the new Silo storage system.
     */
    function seasonToStem(uint256 seedsPerBdv, uint32 season)
        internal
        view
        returns (int96 stem)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        
        require(seedsPerBdv > 0, "Silo: Token not supported");

        //need to go back in time, calculate the delta between the current season and that old deposit season,
        //and that's how many seasons back we need to go. Then, multiply that by seedsPerBdv, and that's our
        //negative grown stalk index.

        //find the difference between the input season and the Silo v3 epoch season
        stem = (int96(season).sub(int96(s.season.stemStartSeason))).mul(int96(seedsPerBdv));
    }

    /** 
     * @notice Migrates farmer's deposits from old (seasons based) to new silo (stems based).
     * @param account Address of the account to migrate
     *
     * @dev If a user's lastUpdate was set, which means they previously had deposits in the silo.
     * if they currently do not have any deposits to migrate, then this function 
     * can be used to migrate their account to the new silo cheaply.
     */
   function _migrateNoDeposits(address account) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        require(s.a[account].s.seeds == 0, "only for zero seeds");
        
        require(LibSilo.migrationNeeded(account), "no migration needed");

        s.a[account].lastUpdate = s.season.stemStartSeason;
    }

    /** 
     * @notice Migrates farmer's deposits from old (seasons based) to new silo (stems based).
     * @param account Address of the account to migrate
     * @param tokens Array of tokens to migrate
     * @param seasons The seasons in which the deposits were made
     * @param amounts The amounts of those deposits which are to be migrated
     *
     * @dev When migrating an account, you must submit all of the account's deposits,
     * or the migration will not pass because the seed check will fail. The seed check
     * adds up the BDV of all submitted deposits, and multiples by the corresponding
     * seed amount for each token type, then compares that to the total seeds stored for that user.
     * If everything matches, we know all deposits were submitted, and the migration is valid.
     *
     * Deposits are migrated to the stem storage system on a 1:1 basis. Accounts with
     * lots of deposits may take a considerable amount of gas to migrate.
     * 
     * Returns seeds diff compared to stored amount, for verification in merkle check.
     */
    function _mowAndMigrate(
        address account, 
        address[] calldata tokens, 
        uint32[][] calldata seasons,
        uint256[][] calldata amounts
    ) internal returns (uint256) {
        //The balanceOfSeeds(account) > 0 check is necessary if someone updates their Silo
        //in the same Season as BIP execution. Such that s.a[account].lastUpdate == s.season.stemStartSeason,
        //but they have not migrated yet
        require((LibSilo.migrationNeeded(account) || balanceOfSeeds(account) > 0), "no migration needed");


        //do a legacy mow using the old silo seasons deposits
        LibSilo.mintGrownStalk(account, balanceOfGrownStalkUpToStemsDeployment(account)); //should only mint stalk up to stemStartSeason
        updateLastUpdateToNow(account);
        //at this point we've completed the guts of the old mow function, now we need to do the migration
 
        MigrateData memory migrateData;
 
        // use of PerTokenData and PerDepositData structs to save on stack depth
        for (uint256 i = 0; i < tokens.length; i++) {
            PerTokenData memory perTokenData;
            perTokenData.token = tokens[i];
            perTokenData.stemTip = LibTokenSilo.stemTipForToken(perTokenData.token);
 
            for (uint256 j = 0; j < seasons[i].length; j++) {
                PerDepositData memory perDepositData;
                perDepositData.season = seasons[i][j];
                perDepositData.amount = amounts[i][j].toUint128();
 
                if (perDepositData.amount == 0) {
                    // skip deposit calculations if amount deposited in deposit is 0
                    continue;
                }
 
                // withdraw this deposit
                uint256 crateBDV = removeDepositFromAccount(
                                    account,
                                    perTokenData.token,
                                    perDepositData.season,
                                    perDepositData.amount
                                );
 
                //calculate how much stalk has grown for this deposit
                perDepositData.grownStalk = _calcGrownStalkForDeposit(
                    crateBDV.mul(getSeedsPerToken(address(perTokenData.token))),
                    perDepositData.season
                );
 
                // also need to calculate how much stalk has grown since the migration
                uint128 stalkGrownSinceStemStartSeason = LibSilo.stalkReward(0, perTokenData.stemTip, crateBDV.toUint128()).toUint128();
                perDepositData.grownStalk = perDepositData.grownStalk.add(stalkGrownSinceStemStartSeason);
                migrateData.totalGrownStalk = migrateData.totalGrownStalk.add(stalkGrownSinceStemStartSeason);
 
                // add to new silo
                LibTokenSilo.addDepositToAccount(
                    account, 
                    perTokenData.token, 
                    LibTokenSilo.grownStalkAndBdvToStem(
                        perTokenData.token, 
                        perDepositData.grownStalk,
                        crateBDV
                    ), 
                    perDepositData.amount, 
                    crateBDV,
                    LibTokenSilo.Transfer.emitTransferSingle
                );

                // Include Deposit in the total Deposited BDV.
                LibTokenSilo.incrementTotalDepositedBdv(perTokenData.token, crateBDV);
 
                // add to running total of seeds
                migrateData.totalSeeds = migrateData.totalSeeds.add(crateBDV.mul(getSeedsPerToken(address(perTokenData.token))).toUint128());

                // emit legacy RemoveDeposit event
                emit RemoveDeposit(account, perTokenData.token, perDepositData.season, perDepositData.amount);
            }
 
            // init mow status for this token
            setMowStatus(account, perTokenData.token, perTokenData.stemTip);
        }
 
        // user deserves stalk grown between stemStartSeason and now
        LibSilo.mintGrownStalk(account, migrateData.totalGrownStalk);

        //return seeds diff for checking in the "part 2" of this function (stack depth kept it from all fitting in one)
        return balanceOfSeeds(account).sub(migrateData.totalSeeds);
    }

    function _mowAndMigrateMerkleCheck(
        address account,
        uint256 stalkDiff,
        uint256 seedsDiff,
        bytes32[] calldata proof,
        uint256 seedsVariance
    ) internal {
        if (seedsDiff > 0) {
            //verify merkle tree to determine stalk/seeds diff drift from convert issue
            bytes32 leaf = keccak256(abi.encode(account, stalkDiff, seedsDiff));
            
            require(
                MerkleProof.verify(proof, DISCREPANCY_MERKLE_ROOT, leaf),
                "UnripeClaim: invalid proof"
            );
        }

        //make sure seedsVariance equals seedsDiff input
        require(seedsVariance == seedsDiff, "seeds misalignment, double check submitted deposits");

        AppStorage storage s = LibAppStorage.diamondStorage();

        //emit that all their seeds are gone, note need to take into account seedsDiff
        emit SeedsBalanceChanged(account, -int256(s.a[account].s.seeds));

        //and wipe out old seed balances (all your seeds are belong to stem)
        setBalanceOfSeeds(account, 0);

        //stalk diff was calculated based on ENROOT_FIX_SEASON, so we need to calculate
        //the amount of stalk that has grown since then
        if (seedsDiff > 0) {
            uint256 currentStalkDiff = (uint256(s.season.current).sub(ENROOT_FIX_SEASON)).mul(seedsDiff).add(stalkDiff);

            //emit the stalk variance
            if (currentStalkDiff > 0) {
                LibSilo.burnStalk(account, currentStalkDiff);
            }
        }
    }

    /**
     * @dev Updates the lastStem of a given token for an account to the latest Tip.
     */
    function setMowStatus(address account, address token, int96 stemTip) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.a[account].mowStatuses[token].lastStem = stemTip;
    }

    /**
     * @dev Season getter.
     */
    function _season() internal view returns (uint32) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.season.current;
    }

    /**
     * @notice DEPRECATED: Seeds do not exist in the new system, but will remain as a
     * user facing concept for the time being.
     * 
     * @dev Legacy Seed balance getter.
     * 
     */
    function balanceOfSeeds(address account) internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.a[account].s.seeds;
    }

    /**
     * @notice DEPRECATED: Seeds do not exist in the new system,
     * but will remain as a user facing concept for the time being.
     * 
     * @dev sets the seed for an given account.
     * 
     */
    function setBalanceOfSeeds(address account, uint256 seeds) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.a[account].s.seeds = seeds;
    }

    /**
     * @dev Updates `lastUpdate` of an account to the current season.
     */
    function updateLastUpdateToNow(address account) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.a[account].lastUpdate = _season();
    }

    /**
     * @dev Calculates the amount of stalk thats been grown for a given deposit.
     */
    function _calcGrownStalkForDeposit(
        uint256 seedsForDeposit,
        uint32 season
    ) internal view returns (uint128 grownStalk) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint32 stemStartSeason = uint32(s.season.stemStartSeason);
        return uint128(stalkReward(seedsForDeposit, stemStartSeason - season));
    }

    /**
     * @dev Legacy Seed balance getter.
     * 
     * constants are used in favor of reading from storage for gas savings.
     */
    function getSeedsPerToken(address token) internal pure returns (uint256) {
        if (token == C.BEAN) {
            return 2;
        } else if (token == C.UNRIPE_BEAN) {
            return 2;
        } else if (token == C.UNRIPE_LP) {
            return 4;
        } else if (token == C.CURVE_BEAN_METAPOOL) {
            return 4;
        }
        return 0;
    }

    ////////////////////////// CLAIM ///////////////////////////////

    /** 
     * @notice DEPRECATED. Internal logic for claiming a singular deposit.
     * 
     * @dev The Zero Withdraw update removed the two-step withdraw & claim process. 
     * These internal functions are left for backwards compatibility, to allow pending 
     * withdrawals from before the update to be claimed.
     */
    function _claimWithdrawal(
        address account,
        address token,
        uint32 season
    ) internal returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 amount = _removeTokenWithdrawal(account, token, season);
        s.siloBalances[token].withdrawn = s.siloBalances[token].withdrawn.sub(
            amount
        );
        emit RemoveWithdrawal(msg.sender, token, season, amount);
        return amount;
    }

    /** 
     * @notice DEPRECATED. Internal logic for claiming multiple deposits.
     * 
     * @dev The Zero Withdraw update removed the two-step withdraw & claim process. 
     * These internal functions are left for backwards compatibility, to allow pending 
     * withdrawals from before the update to be claimed.
     */
    function _claimWithdrawals(
        address account,
        address token,
        uint32[] calldata seasons
    ) internal returns (uint256 amount) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        
        for (uint256 i; i < seasons.length; ++i) {
            amount = amount.add(
                _removeTokenWithdrawal(account, token, seasons[i])
            );
        }
        s.siloBalances[token].withdrawn = s.siloBalances[token].withdrawn.sub(
            amount
        );
        emit RemoveWithdrawals(msg.sender, token, seasons, amount);
        return amount;
    }

    /** 
     * @notice DEPRECATED. Internal logic for removing the claim multiple deposits.
     * 
     * @dev The Zero Withdraw update removed the two-step withdraw & claim process. 
     * These internal functions are left for backwards compatibility, to allow pending 
     * withdrawals from before the update to be claimed.
     */
    function _removeTokenWithdrawal(
        address account,
        address token,
        uint32 season
    ) private returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        require(
            season <= s.season.current,
            "Claim: Withdrawal not receivable"
        );
        uint256 amount = s.a[account].withdrawals[token][season];
        delete s.a[account].withdrawals[token][season];
        return amount;
    }
}

File 10 of 41 : LibConvert.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {LibCurveConvert} from "./LibCurveConvert.sol";
import {LibUnripeConvert} from "./LibUnripeConvert.sol";
import {LibLambdaConvert} from "./LibLambdaConvert.sol";
import {LibConvertData} from "./LibConvertData.sol";
import {C} from "contracts/C.sol";

/**
 * @title LibConvert
 * @author Publius
 */
library LibConvert {
    using SafeMath for uint256;
    using LibConvertData for bytes;

    /**
     * @notice Takes in bytes object that has convert input data encoded into it for a particular convert for
     * a specified pool and returns the in and out convert amounts and token addresses and bdv
     * @param convertData Contains convert input parameters for a specified convert
     */
    function convert(bytes calldata convertData)
        internal
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        LibConvertData.ConvertKind kind = convertData.convertKind();

        if (kind == LibConvertData.ConvertKind.BEANS_TO_CURVE_LP) {
            (tokenOut, tokenIn, amountOut, amountIn) = LibCurveConvert
                .convertBeansToLP(convertData);
        } else if (kind == LibConvertData.ConvertKind.CURVE_LP_TO_BEANS) {
            (tokenOut, tokenIn, amountOut, amountIn) = LibCurveConvert
                .convertLPToBeans(convertData);
        } else if (kind == LibConvertData.ConvertKind.UNRIPE_BEANS_TO_UNRIPE_LP) {
            (tokenOut, tokenIn, amountOut, amountIn) = LibUnripeConvert
                .convertBeansToLP(convertData);
        } else if (kind == LibConvertData.ConvertKind.UNRIPE_LP_TO_UNRIPE_BEANS) {
            (tokenOut, tokenIn, amountOut, amountIn) = LibUnripeConvert
                .convertLPToBeans(convertData);
        } else if (kind == LibConvertData.ConvertKind.LAMBDA_LAMBDA) {
            (tokenOut, tokenIn, amountOut, amountIn) = LibLambdaConvert
                .convert(convertData);
        } else {
            revert("Convert: Invalid payload");
        }
    }

    function getMaxAmountIn(address tokenIn, address tokenOut)
        internal
        view
        returns (uint256)
    {
        /// BEAN:3CRV LP -> BEAN
        if (tokenIn == C.CURVE_BEAN_METAPOOL && tokenOut == C.BEAN)
            return LibCurveConvert.lpToPeg(C.CURVE_BEAN_METAPOOL);
        
        /// BEAN -> BEAN:3CRV LP
        if (tokenIn == C.BEAN && tokenOut == C.CURVE_BEAN_METAPOOL)
            return LibCurveConvert.beansToPeg(C.CURVE_BEAN_METAPOOL);
        
        /// urBEAN:3CRV LP -> urBEAN
        if (tokenIn == C.UNRIPE_LP && tokenOut == C.UNRIPE_BEAN)
            return LibUnripeConvert.lpToPeg();

        /// urBEAN -> urBEAN:3CRV LP
        if (tokenIn == C.UNRIPE_BEAN && tokenOut == C.UNRIPE_LP)
            return LibUnripeConvert.beansToPeg();

        // Lambda -> Lambda
        if (tokenIn == tokenOut) 
            return type(uint256).max;

        revert("Convert: Tokens not supported");
    }

    function getAmountOut(address tokenIn, address tokenOut, uint256 amountIn)
        internal
        view
        returns (uint256)
    {
        /// BEAN:3CRV LP -> BEAN
        if (tokenIn == C.CURVE_BEAN_METAPOOL && tokenOut == C.BEAN)
            return LibCurveConvert.getBeanAmountOut(C.CURVE_BEAN_METAPOOL, amountIn);
        
        /// BEAN -> BEAN:3CRV LP
        if (tokenIn == C.BEAN && tokenOut == C.CURVE_BEAN_METAPOOL)
            return LibCurveConvert.getLPAmountOut(C.CURVE_BEAN_METAPOOL, amountIn);

        /// urBEAN:3CRV LP -> urBEAN
        if (tokenIn == C.UNRIPE_LP && tokenOut == C.UNRIPE_BEAN)
            return LibUnripeConvert.getBeanAmountOut(amountIn);
        
        /// urBEAN -> urBEAN:3CRV LP
        if (tokenIn == C.UNRIPE_BEAN && tokenOut == C.UNRIPE_LP)
            return LibUnripeConvert.getLPAmountOut(amountIn);
        
        // Lambda -> Lambda
        if (tokenIn == tokenOut)
            return amountIn;

        revert("Convert: Tokens not supported");
    }
}

File 11 of 41 : 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 12 of 41 : IBean.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

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

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

File 16 of 41 : 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 17 of 41 : 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 18 of 41 : 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 19 of 41 : AppStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @notice System-level 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 (5/32)
        uint256[2] balances;
        uint256 timestamp;
    }

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

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

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

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

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

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

/**
 * @title AppStorage
 * @author Publius
 * @notice Defines the state object for Beanstalk.
 * @param deprecated_index DEPRECATED: Was the index of the BEAN token in the BEAN:ETH Uniswap V2 pool.
 * @param cases The 24 Weather cases (array has 32 items, but caseId = 3 (mod 4) are not cases)
 * @param paused True if Beanstalk is Paused.
 * @param pausedAt The timestamp at which Beanstalk was last paused.
 * @param season Storage.Season
 * @param c Storage.Contracts
 * @param f Storage.Field
 * @param g Storage.Governance
 * @param co Storage.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 - 2 slots that used to store state variables which have been depreciated through various updates. Storage slots can be left alone or reused.
 * @param newEarnedStalk the amount of earned stalk issued this season. Since 1 stalk = 1 bean, it represents the earned beans as well.
 * @param sops A mapping from Season to Plenty Per Root (PPR) in that Season. Plenty Per Root is 0 if a Season of Plenty did not occur.
 * @param internalTokenBalance A mapping from Farmer address to Token address to Internal Balance. It stores the amount of the Token that the Farmer has stored as an Internal Balance in Beanstalk.
 * @param unripeClaimed True if a Farmer has Claimed an Unripe Token. A mapping from Farmer to Unripe Token to its Claim status.
 * @param u Unripe Settings for a given Token address. The existence of a non-zero Unripe Settings implies that the token is an Unripe Token. The mapping is from Token address to Unripe Settings.
 * @param fertilizer A mapping from Fertilizer Id to the supply of Fertilizer for each Id.
 * @param nextFid A linked list of Fertilizer Ids ordered by Id number. Fertilizer Id is the Beans Per Fertilzer level at which the Fertilizer no longer receives Beans. Sort in order by which Fertilizer Id expires next.
 * @param activeFertilizer The number of active Fertilizer.
 * @param fertilizedIndex The total number of Fertilizer Beans.
 * @param unfertilizedIndex The total number of Unfertilized Beans ever.
 * @param fFirst The lowest active Fertilizer Id (start of linked list that is stored by nextFid). 
 * @param fLast The highest active Fertilizer Id (end of linked list that is stored by nextFid). 
 * @param bpf The cumulative Beans Per Fertilizer (bfp) minted over all Season.
 * @param vestingPeriodRoots the number of roots to add to the global roots, in the case the user plants in the morning. // placed here to save a storage slot.s
 * @param recapitalized The nubmer of USDC that has been recapitalized in the Barn Raise.
 * @param isFarm Stores whether the function is wrapped in the `farm` function (1 if not, 2 if it is).
 * @param ownerCandidate Stores a candidate address to transfer ownership to. The owner must claim the ownership transfer.
 */
struct AppStorage {
    uint8 deprecated_index;
    int8[32] cases; 
    bool paused; // ────────┐ 1 
    uint128 pausedAt; // ───┘ 16 (17/32)
    Storage.Season season;
    Storage.Contracts c;
    Storage.Field f;
    Storage.Governance g;
    Storage.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 (8/32)
    mapping (uint32 => Storage.Fundraiser) fundraisers;
    uint32 fundraiserIndex; // 4 (4/32)
    mapping (address => bool) deprecated_isBudget;
    mapping(uint256 => bytes32) podListings;
    mapping(bytes32 => uint256) podOrders;
    mapping(address => Storage.AssetSilo) siloBalances;
    mapping(address => Storage.SiloSettings) ss;
    uint256[2] deprecated2;
    uint128 newEarnedStalk; // ──────┐ 16
    uint128 vestingPeriodRoots; // ──┘ 16 (32/32)
    mapping (uint32 => uint256) sops;

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

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

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

    // Farm
    uint256 isFarm;

    // Ownership
    address ownerCandidate;
}

File 20 of 41 : 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 21 of 41 : 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 22 of 41 : 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 23 of 41 : SiloExit.sol
/*
/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity =0.7.6;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "contracts/beanstalk/ReentrancyGuard.sol";
import "contracts/libraries/Silo/LibSilo.sol";
import "contracts/libraries/Silo/LibTokenSilo.sol";
import "contracts/libraries/Silo/LibLegacyTokenSilo.sol";
import "contracts/libraries/LibSafeMath32.sol";
import "contracts/libraries/LibSafeMath128.sol";
import "contracts/C.sol";

/**
 * @title SiloExit
 * @author Publius, Brean, Pizzaman1337
 * @notice Exposes public view functions for Silo total balances, account
 * balances, account update history, and Season of Plenty (SOP) balances.
 *
 * Provides utility functions like {_season} for upstream usage throughout
 * SiloFacet.
 */
contract SiloExit is ReentrancyGuard {
    using SafeMath for uint256;
    using LibSafeMath32 for uint32;
    using LibSafeMath128 for uint128;

    /**
     * @dev Stores account-level Season of Plenty balances.
     * 
     * Returned by {balanceOfSop}.
     */
    struct AccountSeasonOfPlenty {
        // The Season that it started Raining, if it was Raining during the last
        // Season in which `account` updated their Silo. Otherwise, 0.
        uint32 lastRain; 
        // The last Season of Plenty starting Season processed for `account`.
        uint32 lastSop;
        // `account` balance of Roots when it started raining. 
        uint256 roots; 
        // The global Plenty per Root at the last Season in which `account`
        // updated their Silo.
        uint256 plentyPerRoot; 
        // `account` balance of unclaimed Bean:3Crv from Seasons of Plenty.
        uint256 plenty; 
    }

    //////////////////////// UTILTIES ////////////////////////

    /**
     * @notice Get the last Season in which `account` updated their Silo.
     */
    function lastUpdate(address account) public view returns (uint32) {
        return s.a[account].lastUpdate;
    }

    //////////////////////// SILO: TOTALS ////////////////////////

    /**
     * @notice Returns the total supply of Stalk. Does NOT include Grown Stalk.
     */
    function totalStalk() public view returns (uint256) {
        return s.s.stalk;
    }

    /**
     * @notice Returns the total supply of Roots.
     */
    function totalRoots() public view returns (uint256) {
        return s.s.roots;
    }

    /**
     * @notice Returns the total supply of Earned Beans.
     * @dev Beanstalk's "supply" of Earned Beans is a subset of the total Bean
     * supply. Earned Beans are simply seignorage Beans held by Beanstalk for 
     * distribution to Stalkholders during {SiloFacet-plant}.   
     */
    function totalEarnedBeans() public view returns (uint256) {
        return s.earnedBeans;
    }

    //////////////////////// SILO: ACCOUNT BALANCES ////////////////////////

    /**
     * @notice Returns the balance of Stalk for `account`. 
     * Does NOT include Grown Stalk.
     * DOES include Earned Stalk.
     * @dev Earned Stalk earns Bean Mints, but Grown Stalk does not due to
     * computational complexity.
     */
    function balanceOfStalk(address account) public view returns (uint256) {
        return s.a[account].s.stalk.add(balanceOfEarnedStalk(account));
    }

    /**
     * @notice Returns the balance of Roots for `account`.
     * @dev Roots within Beanstalk are entirely separate from the 
     * [ROOT ERC-20 token](https://roottoken.org/).
     * 
     * Roots represent proportional ownership of Stalk:
     *  `balanceOfStalk / totalStalk = balanceOfRoots / totalRoots`
     * 
     * Roots are used to calculate Earned Bean, Earned Stalk and Plantable Seed
     * balances.
     *
     * When a Flood occurs, Plenty is distributed based on a Farmer's balance 
     * of Roots when it started Raining.
     */
    function balanceOfRoots(address account) public view returns (uint256) {
        return s.a[account].roots;
    }

    /**
     * @notice Returns the balance of Grown Stalk for `account`. Grown Stalk is 
     * earned each Season from BDV and must be Mown via `SiloFacet-mow` to 
     * apply it to a user's balance.
     * 
     * @dev This passes in the last stem the user mowed at and the current stem
     */
    function balanceOfGrownStalk(address account, address token)
        public
        view
        returns (uint256)
    {
        return
            LibSilo._balanceOfGrownStalk(
                s.a[account].mowStatuses[token].lastStem, //last stem farmer mowed
                LibTokenSilo.stemTipForToken(token), //get latest stem for this token
                s.a[account].mowStatuses[token].bdv
            );
    }

    /**
     * @notice Returns the balance of Grown Stalk for a single deposit of `token`
     * in `stem` for `account`. Grown Stalk is earned each Season from BDV and
     * must be Mown via `SiloFacet-mow` to apply it to a user's balance.
     *
     * @dev This passes in the last stem the user mowed at and the current stem
     */
    function grownStalkForDeposit(
        address account,
        address token,
        int96 stem
    )
        public
        view
        returns (uint grownStalk)
    {
        return LibTokenSilo.grownStalkForDeposit(account, token, stem);
    }
    
    /**
     * @notice Returns the balance of Earned Beans for `account`. Earned Beans
     * are the Beans distributed to Stalkholders during {Sun-rewardToSilo}.
     */
    function balanceOfEarnedBeans(address account)
        public
        view
        returns (uint256 beans)
    {
        beans = _balanceOfEarnedBeans(account, s.a[account].s.stalk);
    }

    /**
     * @dev Internal function to compute `account` balance of Earned Beans.
     *
     * The number of Earned Beans is equal to the difference between: 
     *  - the "expected" Stalk balance, determined from the account balance of 
     *    Roots. 
     *  - the "account" Stalk balance, stored in account storage.
     * divided by the number of Stalk per Bean.
     * The earned beans from the latest season 
     */
    function _balanceOfEarnedBeans(address account, uint256 accountStalk) 
        internal
        view
        returns (uint256 beans) {
        // There will be no Roots before the first Deposit is made.
        if (s.s.roots == 0) return 0;

        uint256 stalk;
        if(LibSilo.inVestingPeriod()){
            stalk = s.s.stalk.sub(s.newEarnedStalk)
                .mul(s.a[account].roots.add(s.a[account].deltaRoots)) // add the delta roots of the user
                .div(s.s.roots.add(s.vestingPeriodRoots)); // add delta of global roots 
        } else {
            stalk = s.s.stalk
                .mul(s.a[account].roots)
                .div(s.s.roots);
        }
        
        // Beanstalk rounds down when minting Roots. Thus, it is possible that
        // balanceOfRoots / totalRoots * totalStalk < s.a[account].s.stalk.
        // As `account` Earned Balance balance should never be negative, 
        // Beanstalk returns 0 instead.
        if (stalk <= accountStalk) return 0;

        // Calculate Earned Stalk and convert to Earned Beans.
        beans = (stalk - accountStalk).div(C.STALK_PER_BEAN); // Note: SafeMath is redundant here.
        if (beans > s.earnedBeans) return s.earnedBeans;

        return beans;
    }

    /**
     * @notice Return the `account` balance of Earned Stalk, the Stalk
     * associated with Earned Beans.
     * @dev Earned Stalk can be derived from Earned Beans because 
     * 1 Bean => 1 Stalk. See {C-getStalkPerBean}.
     */
    function balanceOfEarnedStalk(address account)
        public
        view
        returns (uint256)
    {
        return balanceOfEarnedBeans(account).mul(C.STALK_PER_BEAN);
    }

    //////////////////////// SEASON OF PLENTY ////////////////////////

    /**
     * @notice Returns the last Season that it started Raining resulting in a 
     * Season of Plenty.
     */
    function lastSeasonOfPlenty() public view returns (uint32) {
        return s.season.lastSop;
    }

    /**
     * @notice Returns the `account` balance of unclaimed BEAN:3CRV earned from 
     * Seasons of Plenty.
     */
    function balanceOfPlenty(address account)
        public
        view
        returns (uint256 plenty)
    {
        return LibSilo.balanceOfPlenty(account);
    }

    /**
     * @notice Returns the `account` balance of Roots the last time it was 
     * Raining during a Silo update.
     */
    function balanceOfRainRoots(address account) public view returns (uint256) {
        return s.a[account].sop.roots;
    }

    /**
     * @notice Returns the `account` Season of Plenty related state variables.
     * @dev See {AccountSeasonOfPlenty} struct.
     */
    function balanceOfSop(address account)
        external
        view
        returns (AccountSeasonOfPlenty memory sop)
    {
        sop.lastRain = s.a[account].lastRain;
        sop.lastSop = s.a[account].lastSop;
        sop.roots = s.a[account].sop.roots;
        sop.plenty = balanceOfPlenty(account);
        sop.plentyPerRoot = s.a[account].sop.plentyPerRoot;
    }


    //////////////////////// STEM ////////////////////////

    /**
     * @notice Returns the "stemTip" for a given token.
     * @dev the stemTip is the Cumulative Grown Stalk Per BDV 
     * of a given deposited asset since whitelist. 
     * 
     * note that a deposit for a given asset may have 
     * a higher Grown Stalk Per BDV than the stemTip.
     * 
     * This can occur when a deposit is converted from an asset
     * with a larger seeds per BDV, to a lower seeds per BDV.
     */
    function stemTipForToken(address token)
        public
        view
        returns (int96 _stemTip)
    {
        _stemTip = LibTokenSilo.stemTipForToken(
            token
        );
    }

    /**
     * @notice given the season/token, returns the stem assoicated with that deposit.
     * kept for legacy reasons. 
     */
    function seasonToStem(address token, uint32 season)
        public
        view
        returns (int96 stem)
    {
        uint256 seedsPerBdv = getSeedsPerToken(address(token));
        stem = LibLegacyTokenSilo.seasonToStem(seedsPerBdv, season);
    }

    /**
     * @notice returns the seeds per token, for legacy tokens.
     * calling with an non-legacy token will return 0, 
     * even after the token is whitelisted.
     * kept for legacy reasons. 
     */
    function getSeedsPerToken(address token) public view virtual returns (uint256) {
        return LibLegacyTokenSilo.getSeedsPerToken(token);
    }

    /**
     * @notice returns the season in which beanstalk initalized siloV3.
     */
    function stemStartSeason() public view virtual returns (uint16) {
        return s.season.stemStartSeason;
    }

    /**
     * @notice returns whether an account needs to migrate to siloV3.
     */
    function migrationNeeded(address account) public view returns (bool) {
        return LibSilo.migrationNeeded(account);
    }

    /**
     * @notice Returns true if Earned Beans from the previous
     * Sunrise call are still vesting. 
     * 
     * Vesting Earned Beans cannot be received via `plant()` 
     * until the vesting period is over, and will be forfeited 
     * if a farmer withdraws during the vesting period. 
     */
    function inVestingPeriod() public view returns (bool) {
        return LibSilo.inVestingPeriod();
    }
    //////////////////////// INTERNAL ////////////////////////

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

File 24 of 41 : 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 25 of 41 : 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 26 of 41 : 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 27 of 41 : 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 28 of 41 : LibBytes.sol
/**
 * SPDX-License-Identifier: MIT
 **/
 
pragma solidity =0.7.6;

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

library LibBytes {

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

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


}

File 29 of 41 : 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 30 of 41 : LibSafeMathSigned96.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

        return c;
    }

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

        int96 c = a / b;

        return c;
    }

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

        return c;
    }

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

        return c;
    }
}

File 31 of 41 : LibSafeMathSigned128.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

        return c;
    }

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

        int128 c = a / b;

        return c;
    }

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

        return c;
    }

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

        return c;
    }
}

File 32 of 41 : LibUnripeSilo.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

/**
 * @title LibUnripeSilo
 * @author Publius
 * @notice Contains functions for interacting with Unripe Silo deposits.
 * Provides a unified interface that works across legacy storage references.
 * 
 * @dev Beanstalk was exploited on April 17, 2022. All tokens that existed at
 * this time, including whitelisted LP tokens, are now defunct and referred to 
 * as "legacy" or "pre-exploit" tokens.
 *
 * Legacy token addresses are listed here:
 * https://docs.bean.money/almanac/protocol/contracts#pre-exploit-contracts
 *
 * When Beanstalk was Replanted on Aug 6, 2022, new two tokens — Unripe Bean and 
 * Unripe BEAN:3CRV — were created and whitelisted in the Silo. See {Replant8-init}.
 * 
 * At the time of exploit, there were three forms of LP whitelisted in the Silo:
 * BEAN:ETH, BEAN:3CRV, and BEAN:LUSD. However, only one LP token was created
 * during the Replant: BEAN:3CRV (at a new address). 
 * 
 * Existing Bean and LP Depositors were credited with Unripe Bean Deposits and 
 * Unripe BEAN:3CRV Deposits respectively, equal to the BDV of each Deposit
 * at the end of the pre-exploit block.
 * 
 * {Replant7-init} migrated the Deposits through events by emitting:
 *  1. {RemoveSeason(s)} or {LPRemove} for Bean and LP Deposits
 *  2. {AddDeposit} for Unripe Bean and Unripe LP distributions
 * 
 * This operation was performed for all accounts with Silo Deposits to prevent
 * users from being required to perform a manual migration (and thus pay gas).
 * 
 * However, moving all on-chain Bean Deposit storage variables to the Silo V2 
 * storage mapping during {Replant7-init} was prohibitively expensive.
 *
 * This library remaps pre-exploit Bean and LP Deposit storage references to
 * Unripe Bean and Unripe BEAN:3CRV Deposits. New Unripe Bean and Unripe 
 * BEAN:3CRV Deposits are stored in the expected Silo V2 storage location.
 */
library LibUnripeSilo {
    using SafeMath for uint256;
    using LibSafeMath128 for uint128;

    /*
     * The values below represent the {LibTokenSilo-beanDenominatedValue} of 
     * each pre-exploit LP token at the end of Block 14602789 (the block before 
     * the exploit).
     * 
     * {LibUnripeSilo} uses these constants to migrate pre-exploit LP Deposits.
     * 
     * Note that the BDV of BEAN itself is always 1, hence why only LP tokens
     * appear below.
     */
    
    uint256 private constant AMOUNT_TO_BDV_BEAN_ETH = 119_894_802_186_829; // 18 decimal precision
    uint256 private constant AMOUNT_TO_BDV_BEAN_3CRV = 992_035; // 6 decimal precision
    uint256 private constant AMOUNT_TO_BDV_BEAN_LUSD = 983_108; // 6 decimal precision

    //////////////////////// Unripe BEAN ////////////////////////

    /*
     * Unripe Bean Deposits stored in the Silo V1 Bean storage reference have
     * not yet been Enrooted, as Enrooting moves the Deposit into the Unripe Bean
     * Silo V2 storage reference (See {SiloFacet-enrootDeposit(s)}).
     * 
     * Thus, the BDV of Unripe Bean Deposits stored in the Silo V1 Bean storage 
     * is equal to the amount deposited times the initial % recapitalized when 
     * Beanstalk was Replanted.
     *
     * As Beanstalk continues to recapitalize, users can call 
     * {SiloFacet-enrootDeposit(s)} to update the BDV of their Unripe Deposits. 
     */

    /**
     * @dev Removes all Unripe Beans deposited stored in `account` legacy 
     * Silo V1 storage and returns the BDV.
     *
     * Since Deposited Beans have a BDV of 1, 1 Bean in Silo V1 storage equals
     * 1 Unripe Bean. 
     */
    function removeLegacyUnripeBeanDeposit(
        address account,
        uint32 season
    ) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        delete s.a[account].bean.deposits[season];
    }

    /**
     * @dev Returns true if the provided address is the Unripe Bean address.
     */
    function isUnripeBean(address token) internal pure returns (bool b) {
        b = token == C.UNRIPE_BEAN;
    }

    /**
     * @dev Calculate the `amount` and `bdv` of an Unripe Bean deposit. Sums
     * across the amounts stored in Silo V1 and Silo V2 storage.
     * 
     * This is Unripe Bean equivalent of {LibTokenSilo-tokenDeposit}.
     */
    function unripeBeanDeposit(address account, uint32 season)
        internal
        view
        returns (uint256 amount, uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 legacyAmount = s.a[account].bean.deposits[season];
        
        // Sum the `account` pre-exploit Silo V1 Bean Balance 
        // and the Silo V2 Unripe Bean Balance
        amount = uint256(
            s.a[account].legacyDeposits[C.UNRIPE_BEAN][season].amount
        ).add(legacyAmount);
        
        // Sum the BDV of the `account` pre-exploit Silo V1 Bean Balance 
        // and the BDV value stored in the Unripe Bean Silo V2 storage reference.
        //
        // The BDV of the Silo V1 Bean Balance is equal to the amount of Beans
        // (where 1 Bean = 1 BDV) times the initial recapitalization percent.
        bdv = uint256(s.a[account].legacyDeposits[C.UNRIPE_BEAN][season].bdv)
            .add(legacyAmount.mul(C.initialRecap()).div(1e18));
        
    }
    //////////////////////// Unripe LP ////////////////////////

    /*
     * Unripe LP Deposits stored in the pre-exploit Bean:LUSD and BEAN:3CRV Silo
     * V2 and the BEAN:ETH legacy Silo V1 storage have not been Enrooted, as
     * Enrooting moves the Deposit into the Unripe BEAN:3CRV Silo V2 storage 
     * reference (See {SiloFacet.enrootDeposit(s)}).
     * 
     * Thus, the BDV of Unripe BEAN:3CRV Deposits stored in the Silo V1 Bean
     * storage is equal to the BDV of the amount of token times initial
     * % recapitalized when Beanstalk was Replanted.
     */

    /**
     * @dev Removes all Unripe BEAN:3CRV stored in _any_ of the
     * pre-exploit LP Token Silo storage mappings and returns the BDV. 
     *
     * 
     * 1. Silo V1 format, pre-exploit BEAN:ETH LP token
     * 2. Silo V2 format, pre-exploit BEAN:3CRV LP token
     * 3. Silo V2 format, pre-exploit BEAN:LUSD LP token
     */
    function removeLegacyUnripeLPDeposit(
        address account,
        uint32 season
    ) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        delete s.a[account].lp.depositSeeds[season];
        delete s.a[account].lp.deposits[season];
        delete s.a[account].legacyDeposits[C.unripeLPPool1()][season];
        delete s.a[account].legacyDeposits[C.unripeLPPool2()][season];
    }

    /**1000000000000000017348
     * @dev Returns true if the provided address is the Unripe LP token address.
     */
    function isUnripeLP(address token) internal pure returns (bool b) {
        b = token == C.UNRIPE_LP;
    }

    /**
     * @dev Calculate the `amount` and `bdv` of a given Unripe BEAN:3CRV deposit.
     *
     * This is Unripe LP equivalent of {LibTokenSilo-tokenDeposit}.
     */
    function unripeLPDeposit(address account, uint32 season)
        internal
        view
        returns (uint256 amount, uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        
        // Fetch the amount and BDV stored in all 3 pre-exploit LP Silo Deposit storages.
        // See {getBeanEthUnripeLP}, {getBean3CrvUnripeLP} and {getBeanLusdUnripeLP}
        (amount, bdv) = getBeanEthUnripeLP(account, season);
        (uint256 amount1, uint256 bdv1) = getBean3CrvUnripeLP(account, season);
        (uint256 amount2, uint256 bdv2) = getBeanLusdUnripeLP(account, season);

        // Summate the amount acrosses all 4 potential Unripe BEAN:3CRV storage locations.
        amount = uint256(
            s.a[account].legacyDeposits[C.UNRIPE_LP][season].amount
        ).add(amount.add(amount1).add(amount2));
        
        // Summate the BDV acrosses all 3 pre-exploit LP Silo Deposit storages
        // and haircut by the inital recapitalization percent.
        uint256 legBdv = bdv.add(bdv1).add(bdv2)
            .mul(C.initialRecap())
            .div(C.precision());
        
        // Summate the pre-exploit legacy BDV and the BDV stored in the
        // Unripe BEAN:3CRV Silo Deposit storage.
        bdv = uint256(
            s.a[account].legacyDeposits[C.UNRIPE_LP][season].bdv
        ).add(legBdv);
        
    }

    /*
     * For the following `get*LP()` functions, make note:
     * 
     * @return amount The amount of _Unripe LP_ associated with the pre-exploit 
     * Deposit. Does NOT equal the amount of tokens in the Deposit. Instead,
     * this equals the BDV of all tokens in in this Deposit _at the block 
     * Beanstalk was exploited_.
     * @return bdv The BDV contained in the pre-exploit Deposit.
     */

    /**
     * @dev Calculate the `amount` and `bdv` for a Unripe LP deposit stored in
     * the pre-exploit BEAN:ETH storage location (Silo V1 format).
     *
     * Note: In Silo V1, Beanstalk stored the number of Seeds associated with a 
     * BEAN:ETH LP Deposit instead of the BDV. BDV was then derived as 
     * `seeds / 4`. 
     * 
     * The legacy BEAN:ETH LP token had a precision of 18 decimals.
     */
    function getBeanEthUnripeLP(address account, uint32 season)
        private
        view
        returns (uint256 amount, uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        bdv = s.a[account].lp.depositSeeds[season].div(4);

        // `amount` is equal to the pre-exploit BDV of the Deposited BEAN:ETH
        // tokens. This is the equivalent amount of Unripe BEAN:3CRV LP.
        amount = s
            .a[account]
            .lp
            .deposits[season]
            .mul(AMOUNT_TO_BDV_BEAN_ETH)
            .div(1e18);
    }

    /**
     * @dev Calculate the `amount` and `bdv` for a Unripe LP deposit stored in
     * the pre-exploit BEAN:LUSD storage location (Silo V2 format).
     * 
     * The legacy BEAN:LUSD LP token had a precision of 18 decimals.
     */
    function getBeanLusdUnripeLP(address account, uint32 season)
        private
        view
        returns (uint256 amount, uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        bdv = uint256(s.a[account].legacyDeposits[C.unripeLPPool2()][season].bdv);

        // `amount` is equal to the pre-exploit BDV of the Deposited BEAN:LUSD
        // tokens. This is the equivalent amount of Unripe BEAN:3CRV LP.
        amount = uint256(
            s.a[account].legacyDeposits[C.unripeLPPool2()][season].amount
        ).mul(AMOUNT_TO_BDV_BEAN_LUSD).div(C.precision());
    }

    /**
     * @dev Calculate the `amount` and `bdv` for a Unripe LP deposit stored in 
     * the pre-exploit BEAN:3CRV storage location (Silo V2 format).
     * 
     * The legacy BEAN:3CRV LP token had a precision of 18 decimals.
     */
    function getBean3CrvUnripeLP(address account, uint32 season)
        private
        view
        returns (uint256 amount, uint256 bdv)
    {
        AppStorage storage s = LibAppStorage.diamondStorage();
        bdv = uint256(s.a[account].legacyDeposits[C.unripeLPPool1()][season].bdv);

        // `amount` is equal to the pre-exploit BDV of the Deposited BEAN:3CRV
        // tokens. This is the equivalent amount of Unripe BEAN:3CRV LP.
        amount = uint256(
            s.a[account].legacyDeposits[C.unripeLPPool1()][season].amount
        ).mul(AMOUNT_TO_BDV_BEAN_3CRV).div(C.precision());
    }
}

File 33 of 41 : MerkleProof.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev These functions deal with verification of Merkle trees (hash trees),
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        // Check if the computed hash (root) is equal to the provided root
        return computedHash == root;
    }
}

File 34 of 41 : LibCurveConvert.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {ICurvePool} from "contracts/interfaces/ICurve.sol";
import {LibAppStorage, AppStorage} from "../LibAppStorage.sol";
import {LibConvertData} from "./LibConvertData.sol";
import {LibMetaCurveConvert} from "./LibMetaCurveConvert.sol";
import {C} from "contracts/C.sol";

/**
 * @title LibCurveConvert
 * @author Publius
 */
library LibCurveConvert {
    using SafeMath for uint256;
    using LibConvertData for bytes;

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

    /**
     * @notice Calculate the number of BEAN needed to be added as liquidity to return `pool` back to peg.
     * @dev
     *   Assumes that BEAN is the first token in the pool.
     *   Returns 0 if returns peg.
     */
    function beansToPeg(address pool) internal view returns (uint256 beans) {
        uint256[2] memory balances = ICurvePool(pool).get_balances();
        uint256 xp1 = _getBeansAtPeg(pool, balances);
        if (xp1 <= balances[0]) return 0;
        beans = xp1.sub(balances[0]);
    }

    /**
     * @notice Calculate the amount of liquidity needed to be removed as Beans to return `pool` back to peg.
     * @dev Returns 0 if above peg.
     */
    function lpToPeg(address pool) internal view returns (uint256 lp) {
        uint256[2] memory balances = ICurvePool(pool).get_balances();
        uint256 xp1 = _getBeansAtPeg(pool, balances);
        if (balances[0] <= xp1) return 0;
        return LibMetaCurveConvert.lpToPeg(balances, xp1);
    }

    /**
     * @param pool The address of the Curve pool where `amountIn` will be withdrawn
     * @param amountIn The amount of the LP token of `pool` to remove as BEAN
     * @return beans The amount of BEAN received for removing `amountIn` LP tokens.
     * @dev Assumes that i=0 corresponds to BEAN.
     */
    function getBeanAmountOut(address pool, uint256 amountIn) internal view returns(uint256 beans) {
        beans = ICurvePool(pool).calc_withdraw_one_coin(amountIn, 0); // i=0 -> BEAN
    }

    /**
     * @param pool The address of the Curve pool where `amountIn` will be deposited
     * @param amountIn The amount of BEAN to deposit into `pool`
     * @return lp The amount of LP received for depositing BEAN.
     * @dev Assumes that i=0 corresponds to BEAN.
     */
    function getLPAmountOut(address pool, uint256 amountIn) internal view returns(uint256 lp) {
        lp = ICurvePool(pool).calc_token_amount([amountIn, 0], true); // i=0 -> BEAN
    }

    //////////////////// CURVE CONVERT: KINDS ////////////////////

    /**
     * @notice Decodes convert data and increasing deltaB by removing liquidity as Beans.
     * @param convertData Contains convert input parameters for a Curve AddLPInBeans convert
     */
    function convertLPToBeans(bytes memory convertData)
        internal
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        (uint256 lp, uint256 minBeans, address pool) = convertData
            .convertWithAddress();
        (amountOut, amountIn) = curveRemoveLPAndBuyToPeg(lp, minBeans, pool);
        tokenOut = C.BEAN;
        tokenIn = pool;
    }

    /**
     * @notice Decodes convert data and decreases deltaB by adding Beans as 1-sided liquidity.
     * @param convertData Contains convert input parameters for a Curve AddBeansInLP convert
     */
    function convertBeansToLP(bytes memory convertData)
        internal
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        (uint256 beans, uint256 minLP, address pool) = convertData
            .convertWithAddress();
        (amountOut, amountIn) = curveSellToPegAndAddLiquidity(
            beans,
            minLP,
            pool
        );
        tokenOut = pool;
        tokenIn = C.BEAN;
    }

    //////////////////// CURVE CONVERT: LOGIC ////////////////////

    /**
     * @notice Increase deltaB by adding Beans as liquidity via Curve.
     * @dev deltaB <≈ 0 after the convert
     * @param beans The amount of beans to convert to Curve LP
     * @param minLP The minimum amount of Curve LP to receive
     * @param pool The address of the Curve pool to add to
     */
    function curveSellToPegAndAddLiquidity(
        uint256 beans,
        uint256 minLP,
        address pool
    ) internal returns (uint256 lp, uint256 beansConverted) {
        uint256 beansTo = beansToPeg(pool);
        require(beansTo > 0, "Convert: P must be >= 1.");
        beansConverted = beans > beansTo ? beansTo : beans;
        lp = ICurvePool(pool).add_liquidity([beansConverted, 0], minLP);
    }

    /**
     * @notice Decrease deltaB by removing LP as Beans via Curve.
     * @dev deltaB >≈ 0 after the convert
     * @param lp The amount of Curve LP to be removed
     * @param minBeans The minimum amount of Beans to receive
     * @param pool The address of the Curve pool to remove from
     */
    function curveRemoveLPAndBuyToPeg(
        uint256 lp,
        uint256 minBeans,
        address pool
    ) internal returns (uint256 beans, uint256 lpConverted) {
        uint256 lpTo = lpToPeg(pool);
        require(lpTo > 0, "Convert: P must be < 1.");
        lpConverted = lp > lpTo ? lpTo : lp;
        beans = ICurvePool(pool).remove_liquidity_one_coin(
            lpConverted,
            0,
            minBeans
        );
    }

    //////////////////// INTERNAL ////////////////////
    
    function _getBeansAtPeg(
        address pool,
        uint256[2] memory balances
    ) internal view returns (uint256) {
        if (pool == C.CURVE_BEAN_METAPOOL) {
            return LibMetaCurveConvert.beansAtPeg(balances);
        }

        revert("Convert: Not a whitelisted Curve pool.");
    }
}

File 35 of 41 : LibUnripeConvert.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {C} from "contracts/C.sol";
import {IBean} from "contracts/interfaces/IBean.sol";
import {LibCurveConvert} from "./LibCurveConvert.sol";
import {LibUnripe} from "../LibUnripe.sol";
import {LibConvertData} from "./LibConvertData.sol";
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";

/**
 * @title LibUnripeConvert
 * @author Publius
 */
library LibUnripeConvert {
    using LibConvertData for bytes;
    using SafeMath for uint256;

    function convertLPToBeans(bytes memory convertData)
        internal
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        tokenOut = C.UNRIPE_BEAN;
        tokenIn = C.UNRIPE_LP;
        (uint256 lp, uint256 minBeans) = convertData.basicConvert();

        uint256 minAmountOut = LibUnripe
            .unripeToUnderlying(tokenOut, minBeans)
            .mul(LibUnripe.percentLPRecapped())
            .div(LibUnripe.percentBeansRecapped());

        (
            uint256 outUnderlyingAmount,
            uint256 inUnderlyingAmount
        ) = LibCurveConvert.curveRemoveLPAndBuyToPeg(
                LibUnripe.unripeToUnderlying(tokenIn, lp),
                minAmountOut,
                C.CURVE_BEAN_METAPOOL
            );

        amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount);
        LibUnripe.removeUnderlying(tokenIn, inUnderlyingAmount);
        IBean(tokenIn).burn(amountIn);

        amountOut = LibUnripe
            .underlyingToUnripe(tokenOut, outUnderlyingAmount)
            .mul(LibUnripe.percentBeansRecapped())
            .div(LibUnripe.percentLPRecapped());
        LibUnripe.addUnderlying(tokenOut, outUnderlyingAmount);
        IBean(tokenOut).mint(address(this), amountOut);
    }

    function convertBeansToLP(bytes memory convertData)
        internal
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        tokenIn = C.UNRIPE_BEAN;
        tokenOut = C.UNRIPE_LP;
        (uint256 beans, uint256 minLP) = convertData.basicConvert();

        uint256 minAmountOut = LibUnripe
            .unripeToUnderlying(tokenOut, minLP)
            .mul(LibUnripe.percentBeansRecapped())
            .div(LibUnripe.percentLPRecapped());

        (
            uint256 outUnderlyingAmount,
            uint256 inUnderlyingAmount
        ) = LibCurveConvert.curveSellToPegAndAddLiquidity(
                LibUnripe.unripeToUnderlying(tokenIn, beans),
                minAmountOut,
                C.CURVE_BEAN_METAPOOL
            );

        amountIn = LibUnripe.underlyingToUnripe(tokenIn, inUnderlyingAmount);
        LibUnripe.removeUnderlying(tokenIn, inUnderlyingAmount);
        IBean(tokenIn).burn(amountIn);

        amountOut = LibUnripe
            .underlyingToUnripe(tokenOut, outUnderlyingAmount)
            .mul(LibUnripe.percentLPRecapped())
            .div(LibUnripe.percentBeansRecapped());
        LibUnripe.addUnderlying(tokenOut, outUnderlyingAmount);
        IBean(tokenOut).mint(address(this), amountOut);
    }

    function beansToPeg() internal view returns (uint256 beans) {
        uint256 underlyingBeans = LibCurveConvert.beansToPeg(
            C.CURVE_BEAN_METAPOOL
        );
        beans = LibUnripe.underlyingToUnripe(
            C.UNRIPE_BEAN,
            underlyingBeans
        );
    }

    function lpToPeg() internal view returns (uint256 lp) {
        uint256 underlyingLP = LibCurveConvert.lpToPeg(
            C.CURVE_BEAN_METAPOOL
        );
        lp = LibUnripe.underlyingToUnripe(C.UNRIPE_LP, underlyingLP);
    }

    function getLPAmountOut(uint256 amountIn)
        internal
        view
        returns (uint256 lp)
    {
        uint256 beans = LibUnripe.unripeToUnderlying(
            C.UNRIPE_BEAN,
            amountIn
        );
        lp = LibCurveConvert.getLPAmountOut(C.CURVE_BEAN_METAPOOL, beans);
        lp = LibUnripe
            .underlyingToUnripe(C.UNRIPE_LP, lp)
            .mul(LibUnripe.percentLPRecapped())
            .div(LibUnripe.percentBeansRecapped());
    }

    function getBeanAmountOut(uint256 amountIn)
        internal
        view
        returns (uint256 bean)
    {
        uint256 lp = LibUnripe.unripeToUnderlying(
            C.UNRIPE_LP,
            amountIn
        );
        bean = LibCurveConvert.getBeanAmountOut(C.CURVE_BEAN_METAPOOL, lp);
        bean = LibUnripe
            .underlyingToUnripe(C.UNRIPE_BEAN, bean)
            .mul(LibUnripe.percentBeansRecapped())
            .div(LibUnripe.percentLPRecapped());
    }
}

File 36 of 41 : LibLambdaConvert.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

import {LibConvertData} from "./LibConvertData.sol";

/**
 * @title LibLambdaConvert
 * @author Publius
 */
library LibLambdaConvert {
    using LibConvertData for bytes;

    function convert(bytes memory convertData)
        internal
        pure
        returns (
            address tokenOut,
            address tokenIn,
            uint256 amountOut,
            uint256 amountIn
        )
    {
        (amountIn, tokenIn) = convertData.lambdaConvert();
        tokenOut = tokenIn;
        amountOut = amountIn;
    }
}

File 37 of 41 : LibConvertData.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

/**
 * @title LibConvertData
 * @author LeoFib
 */
library LibConvertData {
    // In order to preserve backwards compatibility, make sure new kinds are added at the end of the enum.
    enum ConvertKind {
        BEANS_TO_CURVE_LP,
        CURVE_LP_TO_BEANS,
        UNRIPE_BEANS_TO_UNRIPE_LP,
        UNRIPE_LP_TO_UNRIPE_BEANS,
        LAMBDA_LAMBDA
    }

    /// @notice Decoder for the Convert Enum
    function convertKind(bytes memory self)
        internal
        pure
        returns (ConvertKind)
    {
        return abi.decode(self, (ConvertKind));
    }

    /// @notice Decoder for the addLPInBeans Convert
    function basicConvert(bytes memory self)
        internal
        pure
        returns (uint256 amountIn, uint256 minAmontOut)
    {
        (, amountIn, minAmontOut) = abi.decode(
            self,
            (ConvertKind, uint256, uint256)
        );
    }

    /// @notice Decoder for the addLPInBeans Convert
    function convertWithAddress(bytes memory self)
        internal
        pure
        returns (
            uint256 amountIn,
            uint256 minAmontOut,
            address token
        )
    {
        (, amountIn, minAmontOut, token) = abi.decode(
            self,
            (ConvertKind, uint256, uint256, address)
        );
    }

    function lambdaConvert(bytes memory self)
        internal
        pure
        returns (uint256 amount, address token)
    {
        (, amount, token) = abi.decode(self, (ConvertKind, uint256, address));
    }
}

File 38 of 41 : LibMetaCurveConvert.sol
// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;
pragma experimental ABIEncoderV2;

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

/**
 * @title LibMetaCurveConvert
 * @author Publius
 */
library LibMetaCurveConvert {
    using SafeMath for uint256;
    using LibConvertData for bytes;

    uint256 constant private N_COINS = 2;
    uint256 constant private FEED2 = 2000000;
    uint256 constant private ADMIN_FEE = 5e9;
    uint256 constant private FEE_DENOMINATOR = 1e10;

    /**
     * @notice Calculate the amount of BEAN that would exist in a Curve metapool
     * if it were "at peg", i.e. if there was 1 BEAN per 1 USD of 3CRV.
     * @dev Assumes that `balances[1]` is 3CRV.
     */
    function beansAtPeg(uint256[2] memory balances)
        internal
        view
        returns (uint256 beans)
    {
        return balances[1].mul(C.curve3Pool().get_virtual_price()).div(1e30);
    }

    function lpToPeg(uint256[2] memory balances, uint256 atPeg) internal view returns (uint256 lp) {
        uint256 a = C.curveMetapool().A_precise();
        uint256[2] memory xp = LibBeanMetaCurve.getXP(balances);
        uint256 d0 = LibCurve.getD(xp, a);
        uint256 toPeg = balances[0].sub(atPeg);
        toPeg = _toPegWithFee(toPeg, balances, d0, a);
        lp = _calcLPTokenAmount(toPeg, balances, d0, a);
    }

    //////////////////// INTERNAL ////////////////////

    function _calcLPTokenAmount(
        uint256 amount,
        uint256[2] memory balances,
        uint256 D0,
        uint256 a
    ) internal view returns (uint256) {
        balances[0] = balances[0].sub(amount);
        uint256[2] memory xp = LibBeanMetaCurve.getXP(balances);
        uint256 D1 = LibCurve.getD(xp, a);
        uint256 diff = D0.sub(D1);
        return diff.mul(C.curveMetapool().totalSupply()).div(D0);
    }

    function _toPegWithFee(
        uint256 amount,
        uint256[2] memory balances,
        uint256 D0,
        uint256 a
    ) internal view returns (uint256) {
        uint256[2] memory xp = LibBeanMetaCurve.getXP(balances);
        uint256 new_y = LibBeanMetaCurve.getXP0(balances[0].sub(amount));
        uint256 D1 = LibCurve.getD([new_y, xp[1]], a);

        uint256[N_COINS] memory xp_reduced;
        uint256 dx_expected = xp[0].mul(D1).div(D0).sub(new_y);
        xp_reduced[0] = xp[0].sub(FEED2.mul(dx_expected) / FEE_DENOMINATOR);

        dx_expected = xp[1].sub(xp[1].mul(D1).div(D0));
        xp_reduced[1] = xp[1].sub(FEED2.mul(dx_expected) / FEE_DENOMINATOR);

        uint256 yd = LibCurve.getYD(a, 0, xp_reduced, D1);
        uint256 dy = xp_reduced[0].sub(yd);
        dy = LibBeanMetaCurve.getX0(dy.sub(1));
        uint256 dy_0 = LibBeanMetaCurve.getX0(xp[0].sub(new_y));

        return dy_0.add(
            dy_0.sub(dy).mul(ADMIN_FEE).div(FEE_DENOMINATOR)
        );
    }
}

File 39 of 41 : 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 40 of 41 : 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 41 of 41 : 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 42 of 41 : 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);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfGrownStalkUpToStemsDeployment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOfLegacySeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32","name":"season","type":"uint32"}],"name":"getDepositLegacy","outputs":[{"internalType":"uint128","name":"","type":"uint128"},{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint32[][]","name":"seasons","type":"uint32[][]"},{"internalType":"uint256[][]","name":"amounts","type":"uint256[][]"},{"internalType":"uint256","name":"stalkDiff","type":"uint256"},{"internalType":"uint256","name":"seedsDiff","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"mowAndMigrate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"mowAndMigrateNoDeposits","outputs":[],"stateMutability":"payable","type":"function"}]

608060405234801561001057600080fd5b50612a12806100206000396000f3fe60806040526004361061005a5760003560e01c8063505f43ea11610043578063505f43ea146100aa578063a9be1acb146100ca578063aed942e9146100f85761005a565b80631be2cfd81461005f5780631f4f3d5514610095575b600080fd5b34801561006b57600080fd5b5061007f61007a366004612528565b61010b565b60405161008c91906126a9565b60405180910390f35b6100a86100a3366004612584565b61011e565b005b3480156100b657600080fd5b5061007f6100c5366004612528565b61014d565b3480156100d657600080fd5b506100ea6100e5366004612542565b610158565b60405161008c9291906128a8565b6100a8610106366004612528565b610209565b600061011682610215565b90505b919050565b600061012f8c8c8c8c8c8c8c610247565b905061013f8c86868686866105f2565b505050505050505050505050565b60006101168261078e565b6000806000610165610831565b905061017085610836565b15610190576000806101828887610858565b909550935061020192505050565b6101998561096f565b156101ab576000806101828887610991565b6001600160a01b0386811660009081526031929092016020908152604080842092881684526010909201815281832063ffffffff8716845290529020546001600160801b038082169350600160801b9091041690505b935093915050565b61021281610ae3565b50565b600080610220610831565b6001600160a01b038416600090815260319091016020526040902060090154915050919050565b600061025288610b9d565b806102655750600061026389610215565b115b61028a5760405162461bcd60e51b815260040161028190612871565b60405180910390fd5b61029c886102978a61078e565b610c27565b6102a588610e36565b6102ad61247d565b60005b878110156105af576102c061247d565b8989838181106102cc57fe5b90506020020160208101906102e19190612528565b6001600160a01b03168082526102f690610e90565b600b90810b900b602082015260005b88888481811061031157fe5b905060200281019061032391906128e1565b905081101561059257610334612494565b89898581811061034057fe5b905060200281019061035291906128e1565b8381811061035c57fe5b9050602002016020810190610371919061266e565b63ffffffff1681526103b088888681811061038857fe5b905060200281019061039a91906128e1565b848181106103a457fe5b90506020020135610f64565b6001600160801b0316602082018190526103ca575061058a565b60006103ed8e8560000151846000015185602001516001600160801b0316610fac565b905061041061040961040286600001516111b2565b8390611270565b83516112d2565b6001600160801b0316604083015260208401516000906104439061043e90839061043986610f64565b6112fc565b610f64565b604084015190915061045e906001600160801b03168261132f565b6001600160801b039081166040850152602088015161047e91168261132f565b87602001906001600160801b031690816001600160801b0316815250506104d68f86600001516104c0886000015187604001516001600160801b031687611395565b86602001516001600160801b03168660006113df565b84516104e2908361167d565b6105106104ff61043e6104f888600001516111b2565b8590611270565b88516001600160801b03169061132f565b87600001906001600160801b031690816001600160801b03168152505084600001516001600160a01b03168f6001600160a01b03167f7dfe6babf78bb003d6561ed598a241a0b419a1f3acbb7ee153888fb60a4c8aa88560000151866020015160405161057e9291906128c2565b60405180910390a35050505b600101610305565b506105a68b82600001518360200151611701565b506001016102b0565b506105c78982602001516001600160801b0316610c27565b80516105e5906001600160801b03166105df8b610215565b9061176b565b9998505050505050505050565b83156106a557600086868660405160200161060f93929190612688565b6040516020818303038152906040528051906020012090506106878484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507fa84dc86252c556839dff46b290f0c401088a65584aa38a163b6b3f7dd7a5b0e892508591506117c89050565b6106a35760405162461bcd60e51b81526004016102819061283a565b505b8381146106c45760405162461bcd60e51b81526004016102819061276f565b60006106ce610831565b6001600160a01b038816600081815260318301602052604080822060090154905193945091927f8a9b067b02389729b43ff012ea79fec02744ec108317c48accb631af39a86a3c926107219203906126a9565b60405180910390a2610734876000611871565b841561078557600381015460009061077190889061076b9089906107659063ffffffff908116906131f99061176b16565b90611270565b9061189f565b905080156107835761078388826118f9565b505b50505050505050565b600080610799610831565b60038101546001600160a01b03851660009081526031830160205260409020600a0154919250600160c01b900461ffff1690640100000000900463ffffffff16818111156107ed5760009350505050610119565b6001600160a01b03851660009081526031840160205260409020600901546108289061082363ffffffff808616908590611bc516565b611c28565b95945050505050565b600090565b6001600160a01b0316731bea0050e63e05fbb5d8ba2f10cf5800b62244491490565b6000806000610865610831565b6001600160a01b0386166000908152603182016020908152604080832063ffffffff808a1680865260038301855283862054731bea0050e63e05fbb5d8ba2f10cf5800b622444987526010909301855283862090865290935292205492935090916108de916001600160801b0390911690839061189f16565b9350610964610900670de0b6b3a76400006108fa6104f8611c3d565b90611c49565b6001600160a01b03881660009081526031850160209081526040808320731bea0050e63e05fbb5d8ba2f10cf5800b62244498452601001825280832063ffffffff8b81168552925290912054600160801b90046001600160801b0316919061189f16565b925050509250929050565b6001600160a01b0316731bea3ccd22f4ebd3d37d731ba31eeca95713716d1490565b600080600061099e610831565b90506109aa8585611cb0565b90935091506000806109bc8787611d62565b915091506000806109cd8989611e50565b9092509050610a406109e38361076b8a8861189f565b6001600160a01b038b1660009081526031880160209081526040808320731bea3ccd22f4ebd3d37d731ba31eeca95713716d8452601001825280832063ffffffff808f1685529252909120546001600160801b0316919061189f16565b96506000610a68610a4f611f01565b6108fa610a5a611c3d565b6107658661076b8d8b61189f565b6001600160a01b038b1660009081526031880160209081526040808320731bea3ccd22f4ebd3d37d731ba31eeca95713716d8452601001825280832063ffffffff8e81168552925290912054919250610ad491600160801b90046001600160801b031690839061189f16565b96505050505050509250929050565b6000610aed610831565b6001600160a01b038316600090815260318201602052604090206009015490915015610b2b5760405162461bcd60e51b8152600401610281906127cc565b610b3482610b9d565b610b505760405162461bcd60e51b815260040161028190612871565b60038101546001600160a01b03929092166000908152603190910160205260409020600a01805467ffffffff000000001916600160c01b90920461ffff1664010000000002919091179055565b600080610ba8610831565b6001600160a01b03841660009081526031820160205260409020600a0154909150640100000000900463ffffffff1615801590610c20575060038101546001600160a01b03841660009081526031830160205260409020600a0154600160c01b90910461ffff1664010000000090910463ffffffff16105b9392505050565b6000610c31610831565b601d810154909150600090610c5957610c52610c4b611f0d565b8490611270565b9050610d3e565b601b820154601d830154610c7291906108fa9086611270565b9050610c7c611f16565b15610d3e57603c820154601b830154601d840154600092610cbe926001600160801b03808316909103926108fa9289926107659291600160801b90041661189f565b90506000610ccd838303610f64565b603c850154909150610cef90600160801b90046001600160801b03168261132f565b603c850180546001600160801b03908116600160801b9382168402179091556001600160a01b03881660009081526031870160205260409020600a018054821693909116909102919091179055505b601b820154610d4d908461189f565b601b8301556001600160a01b0384166000908152603183016020526040902060080154610d7a908461189f565b6001600160a01b0385166000908152603184016020526040902060080155601d820154610da7908261189f565b601d8301556001600160a01b03841660009081526031830160205260409020600e0154610dd4908261189f565b6001600160a01b038516600081815260318501602052604090819020600e019290925590517fb2d61db64b8ad7535308d2111c78934bc32baf9b7cd3a2e58cba25730003cd5890610e2890869085906126b2565b60405180910390a250505050565b6000610e40610831565b9050610e4a611f4f565b6001600160a01b039092166000908152603190910160205260409020600a01805463ffffffff929092166401000000000267ffffffff0000000019909216919091179055565b600080610e9b610831565b6001600160a01b03841660009081526039820160205260409020546003820154919250610f3491620f424091610f2b91610ef59163ffffffff918216600b0b916c01000000000000000000000000909104811690611f6a16565b6001600160a01b038716600090815260398601602052604090205463ffffffff6401000000009091048116600b0b9190611fe216565b600b0b906120b2565b6001600160a01b03909316600090815260399091016020526040902054600160801b9004600b0b91909101919050565b6000600160801b8210610fa85760405162461bcd60e51b81526004018080602001828103825260278152602001806129296027913960400191505060405180910390fd5b5090565b600080610fb7610831565b6001600160a01b0387811660009081526031830160209081526040808320938a1683526010909301815282822063ffffffff89168352905220546001600160801b03600160801b82048116945091925016808411156110815761101986610836565b1561103b576110288786610858565b935090506110368786612187565b611061565b6110448661096f565b15611061576110538786610991565b9350905061106187866121c7565b838110156110815760405162461bcd60e51b815260040161028190612803565b8084101561116c576000611099826108fa8787611270565b905060006110a7858361176b565b905060006110b5848861176b565b90506001600160801b0382118015906110d557506001600160801b038111155b6110f15760405162461bcd60e51b8152600401610281906126db565b6001600160a01b038a8116600090815260319690960160209081526040808820928c1688526010909201815281872063ffffffff8b168852905290942080546001600160801b03928316600160801b029583166fffffffffffffffffffffffffffffffff1990911617909116939093179092555090506111aa565b506001600160a01b03808716600090815260319092016020908152604080842092881684526010909201815281832063ffffffff8716845290528120555b949350505050565b60006001600160a01b03821673bea0000029ad1c77d3d5d23ba2d8893db9d1efab14156111e157506002610119565b6001600160a01b038216731bea0050e63e05fbb5d8ba2f10cf5800b6224449141561120e57506002610119565b6001600160a01b038216731bea3ccd22f4ebd3d37d731ba31eeca95713716d141561123b57506004610119565b6001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49141561126857506004610119565b506000919050565b60008261127f575060006112cc565b8282028284828161128c57fe5b04146112c95760405162461bcd60e51b81526004018080602001828103825260218152602001806129716021913960400191505060405180910390fd5b90505b92915050565b6000806112dd610831565b6003810154909150600160c01b900461ffff1661082885858303611c28565b60008061131a83611311600b87900b88611f6a565b600b0b90611fe2565b600b0b6001600160801b031695945050505050565b60008282016001600160801b0380851690821610156112c9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000806113a185610e90565b905060008084116113b35760006113c5565b6113c56113c08686611c49565b6122a3565b90506113d5600b83900b82611f6a565b9695505050505050565b60006113e9610831565b905060006113f787876122d1565b905061143d61140586610f64565b6001600160a01b038a16600090815260318501602090815260408083208684526019019091529020546001600160801b03169061132f565b6001600160a01b03891660009081526031840160209081526040808320858452601901909152902080546fffffffffffffffffffffffffffffffff19166001600160801b03929092169190911790556114d761149885610f64565b6001600160a01b038a1660009081526031850160209081526040808320868452601901909152902054600160801b90046001600160801b03169061132f565b6001600160a01b03808a166000908152603185016020908152604080832086845260198101835281842080546001600160801b03978816600160801b02908816179055938c168352601a90930190522054611544916c01000000000000000000000000909104168561132f565b6001600160a01b03808a1660009081526031850160209081526040808320938c168352601a909301905290812080546001600160801b03939093166c01000000000000000000000000027fffffffff00000000000000000000000000000000ffffffffffffffffffffffff909316929092179091558360018111156115c557fe5b141561162457876001600160a01b031660006001600160a01b0316336001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62848960405161161b9291906126b2565b60405180910390a45b866001600160a01b0316886001600160a01b03167ff4d42fc7416f300569832aee6989201c613d31d64b823327915a6a33fe7afa5588888860405161166b939291906126c0565b60405180910390a35050505050505050565b6000611687610831565b90506116c661169583610f64565b6001600160a01b0385166000908152603884016020526040902054600160801b90046001600160801b03169061132f565b6001600160a01b03909316600090815260389091016020526040902080546001600160801b03938416600160801b0293169290921790915550565b600061170b610831565b6001600160a01b039485166000908152603190910160209081526040808320959096168252601a909401909352509190208054600b9290920b6bffffffffffffffffffffffff166bffffffffffffffffffffffff19909216919091179055565b6000828211156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600081815b85518110156118665760008682815181106117e457fe5b6020026020010151905080831161182b578281604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120925061185d565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b506001016117cd565b509092149392505050565b600061187b610831565b6001600160a01b039093166000908152603190930160205250604090912060090155565b6000828201838110156112c9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611903610831565b9050816119105750611bc1565b600061191a611f16565b15611a1157603c820154601b830154601d84015461194892909186916001600160801b0316900360016122f8565b6001600160a01b038516600090815260318401602052604081206008810154600a90910154929350909161199191906108fa90600160801b90046001600160801b031687611270565b90506119d361199f82610f64565b6001600160a01b03871660009081526031860160205260409020600a0154600160801b90046001600160801b03169061233e565b6001600160a01b03861660009081526031850160205260409020600a0180546001600160801b03928316600160801b02921691909117905550611a2b565b601b820154601d830154611a2891859060016122f8565b90505b6001600160a01b03841660009081526031830160205260409020600e0154811115611a7057506001600160a01b03831660009081526031820160205260409020600e01545b601b820154611a7f908461176b565b601b8301556001600160a01b0384166000908152603183016020526040902060080154611aac908461176b565b6001600160a01b0385166000908152603184016020526040902060080155601d820154611ad9908261176b565b601d8301556001600160a01b03841660009081526031830160205260409020600e0154611b06908261176b565b6001600160a01b03851660009081526031840160205260409020600e0155600382015471010000000000000000000000000000000000900460ff1615611b8057601a820154611b55908261176b565b601a8301556001600160a01b03841660009081526031830160205260409020600e8101546012909101555b836001600160a01b03167fb2d61db64b8ad7535308d2111c78934bc32baf9b7cd3a2e58cba25730003cd588460000383600003604051610e289291906126b2565b5050565b60008263ffffffff168263ffffffff1611156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b60006112c98363ffffffff8085169061127016565b67029342191969bfcd90565b6000808211611c9f576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611ca857fe5b049392505050565b6000806000611cbd610831565b6001600160a01b0386166000908152603182016020908152604080832063ffffffff808a168552600790910190925290912054919250611d019190600490611c4916565b6001600160a01b0386166000908152603183016020908152604080832063ffffffff808a168552600690910190925290912054919350611d5891670de0b6b3a7640000916108fa9190656d0b2f18424d9061127016565b9250509250929050565b6000806000611d6f610831565b6001600160a01b03861660009081526031820160205260408120919250601090910190611d9a6123a7565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff88168252909252902054600160801b90046001600160801b03169150611d58611de4611f01565b6001600160a01b038716600090815260318401602052604081206108fa91620f23239160100190611e136123a7565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff808d168352935220546001600160801b0316919061127016565b6000806000611e5d610831565b6001600160a01b03861660009081526031820160205260408120919250601090910190611e886123bf565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff88168252909252902054600160801b90046001600160801b03169150611d58611ed2611f01565b6001600160a01b038716600090815260318401602052604081206108fa91620f00449160100190611e136123bf565b670de0b6b3a764000090565b64e8d4a5100090565b600080611f21610831565b60030154600a73010000000000000000000000000000000000000090910463ffffffff164303111592915050565b600080611f5a610831565b6003015463ffffffff1691505090565b6000818303600b83900b8213801590611f89575083600b0b81600b0b13155b80611fa75750600083600b0b128015611fa7575083600b0b81600b0b135b6112c95760405162461bcd60e51b81526004018080602001828103825260248152602001806129b96024913960400191505060405180910390fd5b600082600b0b60001415611ff8575060006112cc565b82600b0b60001914801561201c5750600b82900b6b7fffffffffffffffffffffff19145b156120585760405162461bcd60e51b81526004018080602001828103825260278152602001806129926027913960400191505060405180910390fd5b6000828402905082600b0b84600b0b82600b0b8161207257fe5b05600b0b146112c95760405162461bcd60e51b81526004018080602001828103825260278152602001806129926027913960400191505060405180910390fd5b600081600b0b6000141561210d576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600b0b6000191480156121315750600b83900b6b7fffffffffffffffffffffff19145b1561216d5760405162461bcd60e51b81526004018080602001828103825260218152602001806129506021913960400191505060405180910390fd5b600082600b0b84600b0b8161217e57fe5b05949350505050565b6000612191610831565b6001600160a01b03909316600090815260319093016020908152604080852063ffffffff90941685526003909301905250812055565b60006121d1610831565b6001600160a01b0384166000818152603183016020818152604080842063ffffffff8916855260078101835281852085905560068101835290842084905593835252919250601001906122226123a7565b6001600160a01b0390811682526020808301939093526040918201600090812063ffffffff87168252845282812081905590861681526031840190925281206010019061226d6123bf565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff9095168152939091528220919091555050565b60006b7fffffffffffffffffffffff821115610fa85760405162461bcd60e51b815260040161028190612712565b6bffffffffffffffffffffffff1660609190911b6bffffffffffffffffffffffff19161790565b6000806123068686866123d7565b9050600183600281111561231657fe5b14801561232d57506000848061232857fe5b868809115b156108285760010195945050505050565b6000826001600160801b0316826001600160801b031611156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b733a70dfa7d2262988064a2d051dd47521e43c9bdd90565b73d652c40fbb3f06d6b58cb9aa9cff063ee63d465d90565b6000808060001985870986860292508281109083900303905080612408578382816123fe57fe5b0492505050610c20565b80841161241457600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604080518082019091526000808252602082015290565b604080516060810182526000808252602082018190529181019190915290565b80356001600160a01b038116811461011957600080fd5b60008083601f8401126124dc578182fd5b50813567ffffffffffffffff8111156124f3578182fd5b602083019150836020808302850101111561250d57600080fd5b9250929050565b803563ffffffff8116811461011957600080fd5b600060208284031215612539578081fd5b6112c9826124b4565b600080600060608486031215612556578182fd5b61255f846124b4565b925061256d602085016124b4565b915061257b60408501612514565b90509250925092565b600080600080600080600080600080600060e08c8e0312156125a4578687fd5b6125ad8c6124b4565b9a5067ffffffffffffffff8060208e013511156125c8578788fd5b6125d88e60208f01358f016124cb565b909b50995060408d01358110156125ed578788fd5b6125fd8e60408f01358f016124cb565b909950975060608d0135811015612612578687fd5b6126228e60608f01358f016124cb565b909750955060808d0135945060a08d0135935060c08d0135811015612645578283fd5b506126568d60c08e01358e016124cb565b81935080925050509295989b509295989b9093969950565b60006020828403121561267f578081fd5b6112c982612514565b6001600160a01b039390931683526020830191909152604082015260600190565b90815260200190565b918252602082015260400190565b600b9390930b83526020830191909152604082015260600190565b60208082526017908201527f53696c6f3a2075696e74313238206f766572666c6f772e000000000000000000604082015260600190565b60208082526027908201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160408201527f6e20696e74393600000000000000000000000000000000000000000000000000606082015260800190565b60208082526033908201527f7365656473206d6973616c69676e6d656e742c20646f75626c6520636865636b60408201527f207375626d6974746564206465706f7369747300000000000000000000000000606082015260800190565b60208082526013908201527f6f6e6c7920666f72207a65726f20736565647300000000000000000000000000604082015260600190565b6020808252601c908201527f53696c6f3a2043726174652062616c616e636520746f6f206c6f772e00000000604082015260600190565b6020808252601a908201527f556e72697065436c61696d3a20696e76616c69642070726f6f66000000000000604082015260600190565b60208082526013908201527f6e6f206d6967726174696f6e206e656564656400000000000000000000000000604082015260600190565b6001600160801b0392831681529116602082015260400190565b63ffffffff9290921682526001600160801b0316602082015260400190565b6000808335601e198436030181126128f7578283fd5b83018035915067ffffffffffffffff821115612911578283fd5b602090810192508102360382131561250d57600080fdfe53616665436173743a2076616c756520646f65736e27742066697420696e2031323820626974735369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f77a2646970667358221220ed66a35ff3e1a6a2d5fd64200fb8ee52915ae46d17edb6f026e65dbc6e1d05ec64736f6c63430007060033

Deployed Bytecode

0x60806040526004361061005a5760003560e01c8063505f43ea11610043578063505f43ea146100aa578063a9be1acb146100ca578063aed942e9146100f85761005a565b80631be2cfd81461005f5780631f4f3d5514610095575b600080fd5b34801561006b57600080fd5b5061007f61007a366004612528565b61010b565b60405161008c91906126a9565b60405180910390f35b6100a86100a3366004612584565b61011e565b005b3480156100b657600080fd5b5061007f6100c5366004612528565b61014d565b3480156100d657600080fd5b506100ea6100e5366004612542565b610158565b60405161008c9291906128a8565b6100a8610106366004612528565b610209565b600061011682610215565b90505b919050565b600061012f8c8c8c8c8c8c8c610247565b905061013f8c86868686866105f2565b505050505050505050505050565b60006101168261078e565b6000806000610165610831565b905061017085610836565b15610190576000806101828887610858565b909550935061020192505050565b6101998561096f565b156101ab576000806101828887610991565b6001600160a01b0386811660009081526031929092016020908152604080842092881684526010909201815281832063ffffffff8716845290529020546001600160801b038082169350600160801b9091041690505b935093915050565b61021281610ae3565b50565b600080610220610831565b6001600160a01b038416600090815260319091016020526040902060090154915050919050565b600061025288610b9d565b806102655750600061026389610215565b115b61028a5760405162461bcd60e51b815260040161028190612871565b60405180910390fd5b61029c886102978a61078e565b610c27565b6102a588610e36565b6102ad61247d565b60005b878110156105af576102c061247d565b8989838181106102cc57fe5b90506020020160208101906102e19190612528565b6001600160a01b03168082526102f690610e90565b600b90810b900b602082015260005b88888481811061031157fe5b905060200281019061032391906128e1565b905081101561059257610334612494565b89898581811061034057fe5b905060200281019061035291906128e1565b8381811061035c57fe5b9050602002016020810190610371919061266e565b63ffffffff1681526103b088888681811061038857fe5b905060200281019061039a91906128e1565b848181106103a457fe5b90506020020135610f64565b6001600160801b0316602082018190526103ca575061058a565b60006103ed8e8560000151846000015185602001516001600160801b0316610fac565b905061041061040961040286600001516111b2565b8390611270565b83516112d2565b6001600160801b0316604083015260208401516000906104439061043e90839061043986610f64565b6112fc565b610f64565b604084015190915061045e906001600160801b03168261132f565b6001600160801b039081166040850152602088015161047e91168261132f565b87602001906001600160801b031690816001600160801b0316815250506104d68f86600001516104c0886000015187604001516001600160801b031687611395565b86602001516001600160801b03168660006113df565b84516104e2908361167d565b6105106104ff61043e6104f888600001516111b2565b8590611270565b88516001600160801b03169061132f565b87600001906001600160801b031690816001600160801b03168152505084600001516001600160a01b03168f6001600160a01b03167f7dfe6babf78bb003d6561ed598a241a0b419a1f3acbb7ee153888fb60a4c8aa88560000151866020015160405161057e9291906128c2565b60405180910390a35050505b600101610305565b506105a68b82600001518360200151611701565b506001016102b0565b506105c78982602001516001600160801b0316610c27565b80516105e5906001600160801b03166105df8b610215565b9061176b565b9998505050505050505050565b83156106a557600086868660405160200161060f93929190612688565b6040516020818303038152906040528051906020012090506106878484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507fa84dc86252c556839dff46b290f0c401088a65584aa38a163b6b3f7dd7a5b0e892508591506117c89050565b6106a35760405162461bcd60e51b81526004016102819061283a565b505b8381146106c45760405162461bcd60e51b81526004016102819061276f565b60006106ce610831565b6001600160a01b038816600081815260318301602052604080822060090154905193945091927f8a9b067b02389729b43ff012ea79fec02744ec108317c48accb631af39a86a3c926107219203906126a9565b60405180910390a2610734876000611871565b841561078557600381015460009061077190889061076b9089906107659063ffffffff908116906131f99061176b16565b90611270565b9061189f565b905080156107835761078388826118f9565b505b50505050505050565b600080610799610831565b60038101546001600160a01b03851660009081526031830160205260409020600a0154919250600160c01b900461ffff1690640100000000900463ffffffff16818111156107ed5760009350505050610119565b6001600160a01b03851660009081526031840160205260409020600901546108289061082363ffffffff808616908590611bc516565b611c28565b95945050505050565b600090565b6001600160a01b0316731bea0050e63e05fbb5d8ba2f10cf5800b62244491490565b6000806000610865610831565b6001600160a01b0386166000908152603182016020908152604080832063ffffffff808a1680865260038301855283862054731bea0050e63e05fbb5d8ba2f10cf5800b622444987526010909301855283862090865290935292205492935090916108de916001600160801b0390911690839061189f16565b9350610964610900670de0b6b3a76400006108fa6104f8611c3d565b90611c49565b6001600160a01b03881660009081526031850160209081526040808320731bea0050e63e05fbb5d8ba2f10cf5800b62244498452601001825280832063ffffffff8b81168552925290912054600160801b90046001600160801b0316919061189f16565b925050509250929050565b6001600160a01b0316731bea3ccd22f4ebd3d37d731ba31eeca95713716d1490565b600080600061099e610831565b90506109aa8585611cb0565b90935091506000806109bc8787611d62565b915091506000806109cd8989611e50565b9092509050610a406109e38361076b8a8861189f565b6001600160a01b038b1660009081526031880160209081526040808320731bea3ccd22f4ebd3d37d731ba31eeca95713716d8452601001825280832063ffffffff808f1685529252909120546001600160801b0316919061189f16565b96506000610a68610a4f611f01565b6108fa610a5a611c3d565b6107658661076b8d8b61189f565b6001600160a01b038b1660009081526031880160209081526040808320731bea3ccd22f4ebd3d37d731ba31eeca95713716d8452601001825280832063ffffffff8e81168552925290912054919250610ad491600160801b90046001600160801b031690839061189f16565b96505050505050509250929050565b6000610aed610831565b6001600160a01b038316600090815260318201602052604090206009015490915015610b2b5760405162461bcd60e51b8152600401610281906127cc565b610b3482610b9d565b610b505760405162461bcd60e51b815260040161028190612871565b60038101546001600160a01b03929092166000908152603190910160205260409020600a01805467ffffffff000000001916600160c01b90920461ffff1664010000000002919091179055565b600080610ba8610831565b6001600160a01b03841660009081526031820160205260409020600a0154909150640100000000900463ffffffff1615801590610c20575060038101546001600160a01b03841660009081526031830160205260409020600a0154600160c01b90910461ffff1664010000000090910463ffffffff16105b9392505050565b6000610c31610831565b601d810154909150600090610c5957610c52610c4b611f0d565b8490611270565b9050610d3e565b601b820154601d830154610c7291906108fa9086611270565b9050610c7c611f16565b15610d3e57603c820154601b830154601d840154600092610cbe926001600160801b03808316909103926108fa9289926107659291600160801b90041661189f565b90506000610ccd838303610f64565b603c850154909150610cef90600160801b90046001600160801b03168261132f565b603c850180546001600160801b03908116600160801b9382168402179091556001600160a01b03881660009081526031870160205260409020600a018054821693909116909102919091179055505b601b820154610d4d908461189f565b601b8301556001600160a01b0384166000908152603183016020526040902060080154610d7a908461189f565b6001600160a01b0385166000908152603184016020526040902060080155601d820154610da7908261189f565b601d8301556001600160a01b03841660009081526031830160205260409020600e0154610dd4908261189f565b6001600160a01b038516600081815260318501602052604090819020600e019290925590517fb2d61db64b8ad7535308d2111c78934bc32baf9b7cd3a2e58cba25730003cd5890610e2890869085906126b2565b60405180910390a250505050565b6000610e40610831565b9050610e4a611f4f565b6001600160a01b039092166000908152603190910160205260409020600a01805463ffffffff929092166401000000000267ffffffff0000000019909216919091179055565b600080610e9b610831565b6001600160a01b03841660009081526039820160205260409020546003820154919250610f3491620f424091610f2b91610ef59163ffffffff918216600b0b916c01000000000000000000000000909104811690611f6a16565b6001600160a01b038716600090815260398601602052604090205463ffffffff6401000000009091048116600b0b9190611fe216565b600b0b906120b2565b6001600160a01b03909316600090815260399091016020526040902054600160801b9004600b0b91909101919050565b6000600160801b8210610fa85760405162461bcd60e51b81526004018080602001828103825260278152602001806129296027913960400191505060405180910390fd5b5090565b600080610fb7610831565b6001600160a01b0387811660009081526031830160209081526040808320938a1683526010909301815282822063ffffffff89168352905220546001600160801b03600160801b82048116945091925016808411156110815761101986610836565b1561103b576110288786610858565b935090506110368786612187565b611061565b6110448661096f565b15611061576110538786610991565b9350905061106187866121c7565b838110156110815760405162461bcd60e51b815260040161028190612803565b8084101561116c576000611099826108fa8787611270565b905060006110a7858361176b565b905060006110b5848861176b565b90506001600160801b0382118015906110d557506001600160801b038111155b6110f15760405162461bcd60e51b8152600401610281906126db565b6001600160a01b038a8116600090815260319690960160209081526040808820928c1688526010909201815281872063ffffffff8b168852905290942080546001600160801b03928316600160801b029583166fffffffffffffffffffffffffffffffff1990911617909116939093179092555090506111aa565b506001600160a01b03808716600090815260319092016020908152604080842092881684526010909201815281832063ffffffff8716845290528120555b949350505050565b60006001600160a01b03821673bea0000029ad1c77d3d5d23ba2d8893db9d1efab14156111e157506002610119565b6001600160a01b038216731bea0050e63e05fbb5d8ba2f10cf5800b6224449141561120e57506002610119565b6001600160a01b038216731bea3ccd22f4ebd3d37d731ba31eeca95713716d141561123b57506004610119565b6001600160a01b03821673c9c32cd16bf7efb85ff14e0c8603cc90f6f2ee49141561126857506004610119565b506000919050565b60008261127f575060006112cc565b8282028284828161128c57fe5b04146112c95760405162461bcd60e51b81526004018080602001828103825260218152602001806129716021913960400191505060405180910390fd5b90505b92915050565b6000806112dd610831565b6003810154909150600160c01b900461ffff1661082885858303611c28565b60008061131a83611311600b87900b88611f6a565b600b0b90611fe2565b600b0b6001600160801b031695945050505050565b60008282016001600160801b0380851690821610156112c9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000806113a185610e90565b905060008084116113b35760006113c5565b6113c56113c08686611c49565b6122a3565b90506113d5600b83900b82611f6a565b9695505050505050565b60006113e9610831565b905060006113f787876122d1565b905061143d61140586610f64565b6001600160a01b038a16600090815260318501602090815260408083208684526019019091529020546001600160801b03169061132f565b6001600160a01b03891660009081526031840160209081526040808320858452601901909152902080546fffffffffffffffffffffffffffffffff19166001600160801b03929092169190911790556114d761149885610f64565b6001600160a01b038a1660009081526031850160209081526040808320868452601901909152902054600160801b90046001600160801b03169061132f565b6001600160a01b03808a166000908152603185016020908152604080832086845260198101835281842080546001600160801b03978816600160801b02908816179055938c168352601a90930190522054611544916c01000000000000000000000000909104168561132f565b6001600160a01b03808a1660009081526031850160209081526040808320938c168352601a909301905290812080546001600160801b03939093166c01000000000000000000000000027fffffffff00000000000000000000000000000000ffffffffffffffffffffffff909316929092179091558360018111156115c557fe5b141561162457876001600160a01b031660006001600160a01b0316336001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62848960405161161b9291906126b2565b60405180910390a45b866001600160a01b0316886001600160a01b03167ff4d42fc7416f300569832aee6989201c613d31d64b823327915a6a33fe7afa5588888860405161166b939291906126c0565b60405180910390a35050505050505050565b6000611687610831565b90506116c661169583610f64565b6001600160a01b0385166000908152603884016020526040902054600160801b90046001600160801b03169061132f565b6001600160a01b03909316600090815260389091016020526040902080546001600160801b03938416600160801b0293169290921790915550565b600061170b610831565b6001600160a01b039485166000908152603190910160209081526040808320959096168252601a909401909352509190208054600b9290920b6bffffffffffffffffffffffff166bffffffffffffffffffffffff19909216919091179055565b6000828211156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600081815b85518110156118665760008682815181106117e457fe5b6020026020010151905080831161182b578281604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120925061185d565b808360405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b506001016117cd565b509092149392505050565b600061187b610831565b6001600160a01b039093166000908152603190930160205250604090912060090155565b6000828201838110156112c9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000611903610831565b9050816119105750611bc1565b600061191a611f16565b15611a1157603c820154601b830154601d84015461194892909186916001600160801b0316900360016122f8565b6001600160a01b038516600090815260318401602052604081206008810154600a90910154929350909161199191906108fa90600160801b90046001600160801b031687611270565b90506119d361199f82610f64565b6001600160a01b03871660009081526031860160205260409020600a0154600160801b90046001600160801b03169061233e565b6001600160a01b03861660009081526031850160205260409020600a0180546001600160801b03928316600160801b02921691909117905550611a2b565b601b820154601d830154611a2891859060016122f8565b90505b6001600160a01b03841660009081526031830160205260409020600e0154811115611a7057506001600160a01b03831660009081526031820160205260409020600e01545b601b820154611a7f908461176b565b601b8301556001600160a01b0384166000908152603183016020526040902060080154611aac908461176b565b6001600160a01b0385166000908152603184016020526040902060080155601d820154611ad9908261176b565b601d8301556001600160a01b03841660009081526031830160205260409020600e0154611b06908261176b565b6001600160a01b03851660009081526031840160205260409020600e0155600382015471010000000000000000000000000000000000900460ff1615611b8057601a820154611b55908261176b565b601a8301556001600160a01b03841660009081526031830160205260409020600e8101546012909101555b836001600160a01b03167fb2d61db64b8ad7535308d2111c78934bc32baf9b7cd3a2e58cba25730003cd588460000383600003604051610e289291906126b2565b5050565b60008263ffffffff168263ffffffff1611156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b60006112c98363ffffffff8085169061127016565b67029342191969bfcd90565b6000808211611c9f576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381611ca857fe5b049392505050565b6000806000611cbd610831565b6001600160a01b0386166000908152603182016020908152604080832063ffffffff808a168552600790910190925290912054919250611d019190600490611c4916565b6001600160a01b0386166000908152603183016020908152604080832063ffffffff808a168552600690910190925290912054919350611d5891670de0b6b3a7640000916108fa9190656d0b2f18424d9061127016565b9250509250929050565b6000806000611d6f610831565b6001600160a01b03861660009081526031820160205260408120919250601090910190611d9a6123a7565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff88168252909252902054600160801b90046001600160801b03169150611d58611de4611f01565b6001600160a01b038716600090815260318401602052604081206108fa91620f23239160100190611e136123a7565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff808d168352935220546001600160801b0316919061127016565b6000806000611e5d610831565b6001600160a01b03861660009081526031820160205260408120919250601090910190611e886123bf565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff88168252909252902054600160801b90046001600160801b03169150611d58611ed2611f01565b6001600160a01b038716600090815260318401602052604081206108fa91620f00449160100190611e136123bf565b670de0b6b3a764000090565b64e8d4a5100090565b600080611f21610831565b60030154600a73010000000000000000000000000000000000000090910463ffffffff164303111592915050565b600080611f5a610831565b6003015463ffffffff1691505090565b6000818303600b83900b8213801590611f89575083600b0b81600b0b13155b80611fa75750600083600b0b128015611fa7575083600b0b81600b0b135b6112c95760405162461bcd60e51b81526004018080602001828103825260248152602001806129b96024913960400191505060405180910390fd5b600082600b0b60001415611ff8575060006112cc565b82600b0b60001914801561201c5750600b82900b6b7fffffffffffffffffffffff19145b156120585760405162461bcd60e51b81526004018080602001828103825260278152602001806129926027913960400191505060405180910390fd5b6000828402905082600b0b84600b0b82600b0b8161207257fe5b05600b0b146112c95760405162461bcd60e51b81526004018080602001828103825260278152602001806129926027913960400191505060405180910390fd5b600081600b0b6000141561210d576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600b0b6000191480156121315750600b83900b6b7fffffffffffffffffffffff19145b1561216d5760405162461bcd60e51b81526004018080602001828103825260218152602001806129506021913960400191505060405180910390fd5b600082600b0b84600b0b8161217e57fe5b05949350505050565b6000612191610831565b6001600160a01b03909316600090815260319093016020908152604080852063ffffffff90941685526003909301905250812055565b60006121d1610831565b6001600160a01b0384166000818152603183016020818152604080842063ffffffff8916855260078101835281852085905560068101835290842084905593835252919250601001906122226123a7565b6001600160a01b0390811682526020808301939093526040918201600090812063ffffffff87168252845282812081905590861681526031840190925281206010019061226d6123bf565b6001600160a01b031681526020808201929092526040908101600090812063ffffffff9095168152939091528220919091555050565b60006b7fffffffffffffffffffffff821115610fa85760405162461bcd60e51b815260040161028190612712565b6bffffffffffffffffffffffff1660609190911b6bffffffffffffffffffffffff19161790565b6000806123068686866123d7565b9050600183600281111561231657fe5b14801561232d57506000848061232857fe5b868809115b156108285760010195945050505050565b6000826001600160801b0316826001600160801b031611156117c2576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b733a70dfa7d2262988064a2d051dd47521e43c9bdd90565b73d652c40fbb3f06d6b58cb9aa9cff063ee63d465d90565b6000808060001985870986860292508281109083900303905080612408578382816123fe57fe5b0492505050610c20565b80841161241457600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b604080518082019091526000808252602082015290565b604080516060810182526000808252602082018190529181019190915290565b80356001600160a01b038116811461011957600080fd5b60008083601f8401126124dc578182fd5b50813567ffffffffffffffff8111156124f3578182fd5b602083019150836020808302850101111561250d57600080fd5b9250929050565b803563ffffffff8116811461011957600080fd5b600060208284031215612539578081fd5b6112c9826124b4565b600080600060608486031215612556578182fd5b61255f846124b4565b925061256d602085016124b4565b915061257b60408501612514565b90509250925092565b600080600080600080600080600080600060e08c8e0312156125a4578687fd5b6125ad8c6124b4565b9a5067ffffffffffffffff8060208e013511156125c8578788fd5b6125d88e60208f01358f016124cb565b909b50995060408d01358110156125ed578788fd5b6125fd8e60408f01358f016124cb565b909950975060608d0135811015612612578687fd5b6126228e60608f01358f016124cb565b909750955060808d0135945060a08d0135935060c08d0135811015612645578283fd5b506126568d60c08e01358e016124cb565b81935080925050509295989b509295989b9093969950565b60006020828403121561267f578081fd5b6112c982612514565b6001600160a01b039390931683526020830191909152604082015260600190565b90815260200190565b918252602082015260400190565b600b9390930b83526020830191909152604082015260600190565b60208082526017908201527f53696c6f3a2075696e74313238206f766572666c6f772e000000000000000000604082015260600190565b60208082526027908201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160408201527f6e20696e74393600000000000000000000000000000000000000000000000000606082015260800190565b60208082526033908201527f7365656473206d6973616c69676e6d656e742c20646f75626c6520636865636b60408201527f207375626d6974746564206465706f7369747300000000000000000000000000606082015260800190565b60208082526013908201527f6f6e6c7920666f72207a65726f20736565647300000000000000000000000000604082015260600190565b6020808252601c908201527f53696c6f3a2043726174652062616c616e636520746f6f206c6f772e00000000604082015260600190565b6020808252601a908201527f556e72697065436c61696d3a20696e76616c69642070726f6f66000000000000604082015260600190565b60208082526013908201527f6e6f206d6967726174696f6e206e656564656400000000000000000000000000604082015260600190565b6001600160801b0392831681529116602082015260400190565b63ffffffff9290921682526001600160801b0316602082015260400190565b6000808335601e198436030181126128f7578283fd5b83018035915067ffffffffffffffff821115612911578283fd5b602090810192508102360382131561250d57600080fdfe53616665436173743a2076616c756520646f65736e27742066697420696e2031323820626974735369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f77a2646970667358221220ed66a35ff3e1a6a2d5fd64200fb8ee52915ae46d17edb6f026e65dbc6e1d05ec64736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.