ETH Price: $2,995.72 (-6.77%)

Contract

0xFEFEFE2cfb089aEF0b0578573eF3CFAbC15f1490

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Transfer Ownersh...2612528872024-10-07 7:53:37470 days ago1728287617IN
0xFEFEFE2c...bC15f1490
0 ETH0.000000630.01
Init2612528762024-10-07 7:53:34470 days ago1728287614IN
0xFEFEFE2c...bC15f1490
0 ETH0.000001220.01

Latest 1 internal transaction

Parent Transaction Hash Block From To
2556215392024-09-20 22:09:27486 days ago1726870167  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Fertilizer

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 100 runs

Other Settings:
shanghai EvmVersion
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "./Internalizer.sol";
import {LibRedundantMath128} from "contracts/libraries/LibRedundantMath128.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {IBeanstalk} from "./Internalizer.sol";

/**
 * @author publius
 * @title Barn Raiser
 */

// Inherits Internalizer thus inherits ERC1155Upgradeable and the uri function
// The end Fert Facet only gets the interface of this contract
contract Fertilizer is Internalizer {
    event ClaimFertilizer(uint256[] ids, uint256 beans);

    using LibRedundantMath256 for uint256;
    using LibRedundantMath128 for uint128;

    /**
     * @notice Initializes the contract.
     * @dev In a future update, the metadata will be fully on chain,
     * and thus the uri will not need to be updated.
     */
    function init() external initializer {
        __Internallize_init("");
    }

    /**
     * @notice Calculates and updates the amount of beans a user should receive
     * given a set of fertilizer ids. Callable only by the Beanstalk contract.
     * @param account - the user to update
     * @param ids - an array of fertilizer ids
     * @param bpf - the current beans per fertilizer
     */
    function beanstalkUpdate(
        address account,
        uint256[] memory ids,
        uint128 bpf
    ) external onlyOwner returns (uint256) {
        return __update(account, ids, uint256(bpf));
    }

    /**
     * @notice Mints a fertilizer to an account using a users specified balance
     * Called from FertilizerFacet.mintFertilizer()
     * @param account - the account to mint to
     * @param id - the id of the fertilizer to mint
     * @param amount - the amount of fertilizer to mint
     * @param bpf - the current beans per fertilizer
     */
    function beanstalkMint(
        address account,
        uint256 id,
        uint128 amount,
        uint128 bpf
    ) external onlyOwner {
        if (_balances[id][account].amount > 0) {
            uint256[] memory ids = new uint256[](1);
            ids[0] = id;
            _update(account, ids, bpf);
        }
        _balances[id][account].lastBpf = bpf;
        _safeMint(account, id, amount, bytes("0"));
    }

    /**
     * @notice hadles state updates before a fertilizer transfer
     * @param from - the account to transfer from
     * @param to - the account to transfer to
     * @param ids - an array of fertilizer ids
     */
    function _beforeTokenTransfer(
        address, // operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory, // amounts
        bytes memory // data
    ) internal virtual override {
        uint256 bpf = uint256(IBeanstalk(owner()).beansPerFertilizer());
        if (from != address(0)) _update(from, ids, bpf);
        _update(to, ids, bpf);
    }

    /**
     * @notice Calculates and transfers the rewarded beans
     * from a set of fertilizer ids to an account's internal balance
     * @param account - the user to update
     * @param ids - an array of fertilizer ids
     * @param bpf - the beans per fertilizer
     */
    function _update(address account, uint256[] memory ids, uint256 bpf) internal {
        uint256 amount = __update(account, ids, bpf);
        if (amount > 0) IBeanstalk(owner()).payFertilizer(account, amount);
    }

    /**
     * @notice Calculates and updates the amount of beans a user should receive
     * given a set of fertilizer ids and the current outstanding total beans per fertilizer
     * @param account - the user to update
     * @param ids - the fertilizer ids
     * @param bpf - the current beans per fertilizer
     * @return beans - the amount of beans to reward the fertilizer owner
     */
    function __update(
        address account,
        uint256[] memory ids,
        uint256 bpf
    ) internal returns (uint256 beans) {
        for (uint256 i; i < ids.length; ++i) {
            uint256 stopBpf = bpf < ids[i] ? bpf : ids[i];
            uint256 deltaBpf = stopBpf - _balances[ids[i]][account].lastBpf;
            if (deltaBpf > 0) {
                beans = beans.add(deltaBpf.mul(_balances[ids[i]][account].amount));
                _balances[ids[i]][account].lastBpf = uint128(stopBpf);
            }
        }
        emit ClaimFertilizer(ids, beans);
    }

    /**
     * @notice Returns the balance of fertilized beans of a fertilizer owner given
      a set of fertilizer ids
     * @param account - the fertilizer owner
     * @param ids - the fertilizer ids 
     * @return beans - the amount of fertilized beans the fertilizer owner has
     */
    function balanceOfFertilized(
        address account,
        uint256[] memory ids
    ) external view returns (uint256 beans) {
        uint256 bpf = uint256(IBeanstalk(owner()).beansPerFertilizer());
        for (uint256 i; i < ids.length; ++i) {
            uint256 stopBpf = bpf < ids[i] ? bpf : ids[i];
            uint256 deltaBpf = stopBpf - _balances[ids[i]][account].lastBpf;
            beans = beans.add(deltaBpf.mul(_balances[ids[i]][account].amount));
        }
    }

    /**
     * @notice Returns the balance of unfertilized beans of a fertilizer owner given
      a set of fertilizer ids
     * @param account - the fertilizer owner
     * @param ids - the fertilizer ids 
     * @return beans - the amount of unfertilized beans the fertilizer owner has
     */
    function balanceOfUnfertilized(
        address account,
        uint256[] memory ids
    ) external view returns (uint256 beans) {
        uint256 bpf = uint256(IBeanstalk(owner()).beansPerFertilizer());
        for (uint256 i; i < ids.length; ++i) {
            if (ids[i] > bpf)
                beans = beans.add(ids[i].sub(bpf).mul(_balances[ids[i]][account].amount));
        }
    }

    /**
     @notice Returns the value remaining to recapitalize beanstalk
     */
    function remaining() public view returns (uint256) {
        return IBeanstalk(owner()).remainingRecapitalization();
    }

    /**
     @notice Returns the id a fertilizer will receive when minted
    */
    function getMintId() public view returns (uint256) {
        return uint256(IBeanstalk(owner()).getEndBpf());
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./Fertilizer1155.sol";
import {LibRedundantMath128} from "contracts/libraries/LibRedundantMath128.sol";
import "./FertilizerImage.sol";
import {LibBytes64} from "contracts/libraries/LibBytes64.sol";

/**
 * @author publius, deadmanwalking
 * @title Fertilizer before the Unpause
 */

// interface to interact with the Beanstalk contract
interface IBeanstalk {
    function payFertilizer(address account, uint256 amount) external;
    function beansPerFertilizer() external view returns (uint128);
    function getEndBpf() external view returns (uint128);
    function remainingRecapitalization() external view returns (uint256);
    function getFertilizer(uint128) external view returns (uint256);
}

contract Internalizer is
    OwnableUpgradeable,
    ReentrancyGuardUpgradeable,
    Fertilizer1155,
    FertilizerImage
{
    using LibRedundantMath128 for uint128;
    using Strings for uint256;

    struct Balance {
        uint128 amount;
        uint128 lastBpf;
    }

    function __Internallize_init(string memory uri_) internal {
        __Ownable_init(msg.sender);
        __ERC1155_init(uri_);
        __ReentrancyGuard_init();
    }

    mapping(uint256 => mapping(address => Balance)) internal _balances;

    string private _uri;

    ///////////////////// NEW URI FUNCTION ///////////////////////

    /**
     * @notice Assembles and returns a base64 encoded json metadata
     * URI for a given fertilizer ID.
     * Need to override because the contract indirectly
     * inherits from ERC1155.
     * @param _id - the id of the fertilizer
     * @return - the json metadata URI
     */
    function uri(uint256 _id) public view virtual override returns (string memory) {
        uint128 bpfRemaining = calculateBpfRemaining(_id);

        // generate the image URI
        string memory imageUri = imageURI(_id, bpfRemaining);

        // assemble and return the json URI
        return (
            string(
                abi.encodePacked(
                    BASE_JSON_URI,
                    LibBytes64.encode(
                        bytes(
                            abi.encodePacked(
                                '{"name": "Fertilizer - ',
                                _id.toString(),
                                '", "external_url": "https://fert.bean.money/',
                                _id.toString(),
                                '.html", ',
                                '"description": "A trusty constituent of any Farmers toolbox, ERC-1155 FERT has been known to spur new growth on seemingly dead farms. Once purchased and deployed into fertile ground by Farmers, Fertilizer generates new Sprouts: future Beans yet to be repaid by Beanstalk in exchange for doing the work of Replanting the protocol.", "image": "',
                                imageUri,
                                '", "attributes": [{ "trait_type": "BPF Remaining","display_type": "boost_number","value": ',
                                formatBpRemaining(bpfRemaining),
                                " }]}"
                            )
                        )
                    )
                )
            )
        );
    }

    /**
     * @notice Returns the beans per fertilizer remaining for a given fertilizer Id.
     * @param id - the id of the fertilizer
     * Formula: bpfRemaining = id - s.bpf
     * Calculated here to avoid uint underflow
     * Solidity 0.8.0 has underflow protection and the tx would revert but we are using 0.7.6
     */
    function calculateBpfRemaining(uint256 id) internal view returns (uint128) {
        // make sure it does not underflow
        if (uint128(id) >= IBeanstalk(BEANSTALK).beansPerFertilizer()) {
            return uint128(id) - IBeanstalk(BEANSTALK).beansPerFertilizer();
        } else {
            return 0;
        }
    }

    function name() external pure returns (string memory) {
        return "Fertilizer";
    }

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

    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        require(account != address(0), "ERC1155: balance query for the zero address");
        return _balances[id][account].amount;
    }

    function lastBalanceOf(address account, uint256 id) public view returns (Balance memory) {
        require(account != address(0), "ERC1155: balance query for the zero address");
        return _balances[id][account];
    }

    function lastBalanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) external view returns (Balance[] memory balances) {
        balances = new Balance[](accounts.length);
        for (uint256 i; i < accounts.length; ++i) {
            balances[i] = lastBalanceOf(accounts[i], ids[i]);
        }
    }

    function _transfer(
        address from,
        address to,
        uint256 id,
        uint256 amount
    ) internal virtual override {
        uint128 _amount = uint128(amount);
        if (from != address(0)) {
            uint128 fromBalance = _balances[id][from].amount;
            require(uint256(fromBalance) >= amount, "ERC1155: insufficient balance for transfer");
            // Because we know fromBalance >= amount, we know amount < type(uint128).max
            _balances[id][from].amount = fromBalance - _amount;
        }
        _balances[id][to].amount = _balances[id][to].amount.add(_amount);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @author Publius, funderbrker
 * @title LibRedundantMath variation of Open Zeppelin's Safe Math library for uint128.
 * @dev Newly developed code should not use this library. Instead opt for native arithmetic operators.
 *
 * This library replicates the behavior of 0.7 SafeMath libraries for 0.8. Safe math is unnecessary
 * in solidity ^0.8, so the functionality here is mostly redundant with default arithmetic
 * operators. However, manually updating over 1000 math operations throughout the repo was
 * deemed too likely to introduce logic errors. Instead, the original syntax was kept
 * and the underlying logic updated to be 0.8 appropriate.
 **/
library LibRedundantMath128 {
    /**
     * @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) {
        return a + b;
    }

    /**
     * @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) {
        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) {
        return a * b;
    }

    /**
     * @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) {
        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) {
        return a % b;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @author Publius, funderbrker
 * @title LibRedundantMath variation of Open Zeppelin's Safe Math library for uint256.
 * @dev Newly developed code should not use this library. Instead opt for native arithmetic operators.
 *
 * This library replicates the behavior of 0.7 SafeMath libraries for 0.8. Safe math is unnecessary
 * in solidity ^0.8, so the functionality here is mostly redundant with default arithmetic
 * operators. However, manually updating over 1000 math operations throughout the repo was
 * deemed too likely to introduce logic errors. Instead, the original syntax was kept
 * and the underlying logic updated to be 0.8 appropriate.
 **/
library LibRedundantMath256 {
    /**
     * @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) {
        return a + b;
    }

    /**
     * @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) {
        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) {
        return a * b;
    }

    /**
     * @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) {
        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) {
        return a % b;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    function __Ownable_init(address initialOwner) internal onlyInitializing {
        __Ownable_init_unchained(initialOwner);
    }

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        OwnableStorage storage $ = _getOwnableStorage();
        return $._owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        OwnableStorage storage $ = _getOwnableStorage();
        address oldOwner = $._owner;
        $._owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity ^0.8.20;

import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {LibFertilizer} from "contracts/libraries/LibFertilizer.sol";

/**
 * @author Publius
 * @dev Fertilizer tailored implemetation of the ERC-1155 standard.
 * We rewrite transfer and mint functions to allow the balance transfer function be overwritten as well.
 */
contract Fertilizer1155 is ERC1155Upgradeable {
    // using Address for address;

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(to != address(0), "ERC1155: transfer to the zero address");
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not owner nor approved"
        );

        address operator = _msgSender();

        _beforeTokenTransfer(
            operator,
            from,
            to,
            __asSingletonArray(id),
            __asSingletonArray(amount),
            data
        );

        _transfer(from, to, id, amount);

        emit TransferSingle(operator, from, to, id, amount);

        __doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: transfer caller is not owner nor approved"
        );

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        for (uint256 i; i < ids.length; ++i) {
            _transfer(from, to, ids[i], amounts[i]);
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        __doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
    }

    function _transfer(address from, address to, uint256 id, uint256 amount) internal virtual {}

    function _safeMint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();

        _transfer(address(0), to, id, amount);

        emit TransferSingle(operator, address(0), to, id, amount);

        __doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    // The 3 functions below are copied from:
    // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/ERC1155.sol)
    // as they are private functions.

    function __doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (LibFertilizer.isContract(to)) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

    function __doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (LibFertilizer.isContract(to)) {
            try
                IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data)
            returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non ERC1155Receiver implementer");
            }
        }
    }

    function __asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
        uint256[] memory array = new uint256[](1);
        array[0] = element;

        return array;
    }

    // Following the 1155 design from OpenZeppelin Contracts < 5.x.
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;
pragma experimental ABIEncoderV2;

import {LibBytes64} from "contracts/libraries/LibBytes64.sol";
import {IBeanstalk} from "./Internalizer.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

/**
 * @title FertilizerImage
 * @author deadmanwalking
 */

contract FertilizerImage {
    using Strings for uint256;
    address internal constant BEANSTALK = 0xC1E088fC1323b20BCBee9bd1B9fC9546db5624C5;

    //////////////////////   CONSTANTS TO ASSEMBLE SVG   ////////////////////////////

    string internal constant BASE_JSON_URI = "data:application/json;base64,";

    // Start for all fert svgs
    string private constant BASE_SVG_START =
        '<path d="M164.47 327.241 28.625 405.768l-.878-221.551 135.849-78.559.874 221.583Z" fill="#3DAA47"/><path d="m118.059 354.077-41.102 23.746-.874-221.551 41.101-23.778.875 221.583Z" fill="#3DAA47"/><path d="m26.825 184.242.87 221.567 93.367 54.339-.871-221.564-93.366-54.342Zm136.432-78.262.871 221.568 93.367 54.338-.871-221.564-93.367-54.342Z" fill="#3DB542"/>';

    // End for all fert svgs
    string private constant BASE_SVG_END =
        '<path d="m256.898 381.609-135.846 78.527-.877-221.551 135.849-78.56.874 221.584Z" fill="#6DCB60"/><path d="m210.486 408.445-41.101 23.745-.875-221.551 41.102-23.778.874 221.584Z" fill="#3DAA47"/><path d="m240.901 364.949-104.407 60.387-.323-157.477 104.408-60.351.322 157.441Z" fill="#fff"/><path d="M195.789 268.025c23.137-6.714 36.875 10.631 32.306 35.233-4.02 21.652-21.352 42.845-39.769 49.821-19.171 7.26-35.717-2.268-36.297-23.966-.665-24.922 19.413-54.021 43.76-61.088Z" fill="#46B955"/><path d="m206.417 275.615-28.08 73.577s-24.569-35.397 28.08-73.577Zm-23.027 68.362 19.561-50.916s23.831 17.189-19.561 50.916Z" fill="#fff"/>';

    // Top for the available fert svg
    string private constant FERT_TOP_AVAILABLE =
        '<path d="M76.634 162.915 212 84.133l44.034 75.909-135.842 78.544-43.557-75.671Z" fill="#81D672"/><path d="m124.966 134.97 40.624-24.001 44.031 75.906-41.098 23.765-43.557-75.67Z" fill="#46B955"/><path d="m212.125 47.918-.116 36.228-135.394 78.766.116-36.17c0-2.032-1.39-4.413-3.13-5.457-.87-.523-1.68-.523-2.261-.233l135.394-78.766c.58-.349 1.332-.29 2.203.233 1.736.989 3.188 3.425 3.188 5.4Z" fill="#6DCB60"/><path d="m165.713 74.752-.116 36.228-40.65 23.988.116-36.17c0-2.032-1.39-4.413-3.129-5.457-.872-.523-1.681-.523-2.262-.232l40.65-23.989c.58-.349 1.332-.29 2.203.233 1.739.986 3.188 3.425 3.188 5.4Z" fill="#42A84C"/><path d="M73.579 121.298c1.739 1.005 3.162 3.422 3.159 5.425l-.104 36.193 43.557 75.667-93.366-54.339 43.521-25.018.103-36.141c.004-2 1.39-2.795 3.13-1.787Z" fill="#2C9A2C"/><path d="M107.879 226.766 36.62 185.565l35.742-20.395 11.428 19.794 24.089 41.802Z" fill="#6DCB60"/><path d="m81.348 180.731-44.728 4.834 35.742-20.395 8.986 15.561Z" fill="#81D672"/>  <path d="M95.493 209.237c-9.447 2.966-17.845 10.637-21.62 21.552-.497 1.589-2.678 1.589-3.272 0-3.272-10.23-11.405-18.276-21.52-21.552-1.784-.598-1.784-2.782 0-3.377 10.115-3.312 18.174-11.506 21.52-21.552.594-1.689 2.778-1.689 3.272 0 3.768 10.689 11.563 18.195 21.62 21.552 1.687.595 1.687 2.779 0 3.377Z" fill="#fff"/>';

    // Top for the active fert svg
    string private constant FERT_TOP_ACTIVE =
        '<ellipse cx="113.247" cy="220.688" rx="38.717" ry="38.774" fill="#7F5533"/><ellipse cx="113.247" cy="220.688" rx="38.717" ry="38.774" fill="#7F5533"/><ellipse cx="70.013" cy="236.844" rx="38.717" ry="38.774" fill="#7F5533"/><path d="m26.825 184.242.87 221.567 93.367 54.339-.871-221.564-93.366-54.342Zm136.432-78.262.871 221.568 93.367 54.338-.871-221.564-93.367-54.342Z" fill="#3DB542"/><ellipse cx="156.805" cy="198.715" rx="38.717" ry="38.774" fill="#7F5533"/><ellipse cx="198.103" cy="189.668" rx="38.717" ry="38.774" fill="#7F5533"/>';

    /**
     * @dev imageURI returns the base64 encoded image URI representation of the Fertilizer
     * @param _id - the id of the Fertilizer
     * @param bpfRemaining - the bpfRemaining of the Fertilizer
     * @return imageUri - the image URI representation of the Fertilizer
     */
    function imageURI(uint256 _id, uint128 bpfRemaining) public view returns (string memory) {
        return svgToImageURI(generateImageSvg(_id, bpfRemaining));
    }

    /////////////// FERTILIZER SVG ORDER ///////////////////
    // SVG_HEADER
    // BASE_SVG_START
    // FERT_SVG_TOP (available, active)
    // BASE_SVG_END
    // SVG_PRE_NUMBER
    // BPF_REMAINING
    // END OF SVG

    /**
     * @dev generateImageSvg assembles the needed components for the Fertilizer svg
     * For use in the on-chain json fertilizer metadata
     * @param _id - the id of the Fertilizer
     * @param bpfRemaining - the bpfRemaining of the Fertilizer
     * @return imageUri - the image URI representation of the Fertilizer
     */
    function generateImageSvg(
        uint256 _id,
        uint128 bpfRemaining
    ) internal view returns (string memory) {
        return
            string(
                abi.encodePacked(
                    '<svg width="294" height="512" viewBox="0 0 294 512" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">', // SVG HEADER
                    BASE_SVG_START,
                    getFertilizerStatusSvg(_id, bpfRemaining), // FERT_SVG_TOP (available, active)
                    BASE_SVG_END,
                    '<text font-family="sans-serif" font-size="20" x="20" y="490" fill="black" ><tspan dy="0" x="20">', // PRE NUMBER FOR BPF REMAINING
                    formatBpRemaining(bpfRemaining), // BPF_REMAINING with 2 decimal places
                    " BPF Remaining </tspan></text></svg>" // END OF SVG
                )
            );
    }

    /**
     * @dev Returns the correct svg top for the Fertilizer status based on the bpfRemaining.
     * @param _id - the id of the Fertilizer
     * @param bpfRemaining - the bpfRemaining of the Fertilizer
     * @return fertilizerStatusSvg an svg top for the correct Fertilizer status
     */
    function getFertilizerStatusSvg(
        uint256 _id,
        uint128 bpfRemaining
    ) internal view returns (string memory) {
        uint256 fertilizerSupply = IBeanstalk(BEANSTALK).getFertilizer(uint128(_id));

        string memory fertilizerStatusSvg = FERT_TOP_AVAILABLE;

        if (fertilizerSupply > 0) {
            fertilizerStatusSvg = bpfRemaining > 0 ? FERT_TOP_ACTIVE : ""; // a used fert (bpfRemaining = 0) has no top
        }

        return fertilizerStatusSvg;
    }

    /// @dev Helper function that converts an svg to a bade64 encoded image URI.
    function svgToImageURI(string memory svg) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "data:image/svg+xml;base64,",
                    LibBytes64.encode(bytes(string(abi.encodePacked(svg))))
                )
            );
    }

    /**
     * @notice Formats a the bpf remaining value with 6 decimals to a string with 2 decimals.
     * @param number - The bpf value to format.
     */
    function formatBpRemaining(uint256 number) internal pure returns (string memory) {
        // 6 to 2 decimal places
        uint256 scaled = number / 10000;
        // Separate the integer and decimal parts
        uint256 integerPart = scaled / 100;
        uint256 decimalPart = scaled % 100;
        string memory result = integerPart.toString();
        // Add decimal point
        result = string(abi.encodePacked(result, "."));
        // Add leading zero if necessary
        if (decimalPart < 10) {
            result = string(abi.encodePacked(result, "0"));
        }
        // Add decimal part
        result = string(abi.encodePacked(result, decimalPart.toString()));
        return result;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

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

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

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

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

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

        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // 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.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            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.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @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) {
        unchecked {
            // 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 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 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.

            uint256 twos = denominator & (0 - denominator);
            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 (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

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

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.20;

import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
import {IERC1155Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 */
abstract contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155, IERC1155MetadataURI, IERC1155Errors {
    using Arrays for uint256[];
    using Arrays for address[];

    /// @custom:storage-location erc7201:openzeppelin.storage.ERC1155
    struct ERC1155Storage {
        mapping(uint256 id => mapping(address account => uint256)) _balances;

        mapping(address account => mapping(address operator => bool)) _operatorApprovals;

        // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
        string _uri;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC1155")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ERC1155StorageLocation = 0x88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4500;

    function _getERC1155Storage() private pure returns (ERC1155Storage storage $) {
        assembly {
            $.slot := ERC1155StorageLocation
        }
    }

    /**
     * @dev See {_setURI}.
     */
    function __ERC1155_init(string memory uri_) internal onlyInitializing {
        __ERC1155_init_unchained(uri_);
    }

    function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
        _setURI(uri_);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256 /* id */) public view virtual returns (string memory) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     */
    function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual returns (uint256[] memory) {
        if (accounts.length != ids.length) {
            revert ERC1155InvalidArrayLength(ids.length, accounts.length);
        }

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
        ERC1155Storage storage $ = _getERC1155Storage();
        return $._operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeTransferFrom(from, to, id, value, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) public virtual {
        address sender = _msgSender();
        if (from != sender && !isApprovedForAll(from, sender)) {
            revert ERC1155MissingApprovalForAll(sender, from);
        }
        _safeBatchTransferFrom(from, to, ids, values, data);
    }

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
     * (or `to`) is the zero address.
     *
     * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
     *   or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
     * - `ids` and `values` must have the same length.
     *
     * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
     */
    function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        if (ids.length != values.length) {
            revert ERC1155InvalidArrayLength(ids.length, values.length);
        }

        address operator = _msgSender();

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids.unsafeMemoryAccess(i);
            uint256 value = values.unsafeMemoryAccess(i);

            if (from != address(0)) {
                uint256 fromBalance = $._balances[id][from];
                if (fromBalance < value) {
                    revert ERC1155InsufficientBalance(from, fromBalance, value, id);
                }
                unchecked {
                    // Overflow not possible: value <= fromBalance
                    $._balances[id][from] = fromBalance - value;
                }
            }

            if (to != address(0)) {
                $._balances[id][to] += value;
            }
        }

        if (ids.length == 1) {
            uint256 id = ids.unsafeMemoryAccess(0);
            uint256 value = values.unsafeMemoryAccess(0);
            emit TransferSingle(operator, from, to, id, value);
        } else {
            emit TransferBatch(operator, from, to, ids, values);
        }
    }

    /**
     * @dev Version of {_update} that performs the token acceptance check by calling
     * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
     * contains code (eg. is a smart contract at the moment of execution).
     *
     * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
     * update to the contract state after this function would break the check-effect-interaction pattern. Consider
     * overriding {_update} instead.
     */
    function _updateWithAcceptanceCheck(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal virtual {
        _update(from, to, ids, values);
        if (to != address(0)) {
            address operator = _msgSender();
            if (ids.length == 1) {
                uint256 id = ids.unsafeMemoryAccess(0);
                uint256 value = values.unsafeMemoryAccess(0);
                _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
            } else {
                _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
            }
        }
    }

    /**
     * @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     * - `ids` and `values` must have the same length.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, to, ids, values, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the values in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        $._uri = newuri;
    }

    /**
     * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
        if (to == address(0)) {
            revert ERC1155InvalidReceiver(address(0));
        }
        _updateWithAcceptanceCheck(address(0), to, ids, values, data);
    }

    /**
     * @dev Destroys a `value` amount of tokens of type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     */
    function _burn(address from, uint256 id, uint256 value) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `value` amount of tokens of type `id`.
     * - `ids` and `values` must have the same length.
     */
    function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
        if (from == address(0)) {
            revert ERC1155InvalidSender(address(0));
        }
        _updateWithAcceptanceCheck(from, address(0), ids, values, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the zero address.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        ERC1155Storage storage $ = _getERC1155Storage();
        if (operator == address(0)) {
            revert ERC1155InvalidOperator(address(0));
        }
        $._operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 value,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
     * if it contains code at the moment of execution.
     */
    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) private {
        if (to.code.length > 0) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    // Tokens rejected
                    revert ERC1155InvalidReceiver(to);
                }
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    // non-ERC1155Receiver implementer
                    revert ERC1155InvalidReceiver(to);
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
     * @dev Creates an array in memory with only one value for each of the elements provided.
     */
    function _asSingletonArrays(
        uint256 element1,
        uint256 element2
    ) private pure returns (uint256[] memory array1, uint256[] memory array2) {
        /// @solidity memory-safe-assembly
        assembly {
            // Load the free memory pointer
            array1 := mload(0x40)
            // Set array length to 1
            mstore(array1, 1)
            // Store the single element at the next word after the length (where content starts)
            mstore(add(array1, 0x20), element1)

            // Repeat for next array locating it right after the first array
            array2 := add(array1, 0x40)
            mstore(array2, 1)
            mstore(add(array2, 0x20), element2)

            // Update the free memory pointer by pointing after the second array
            mstore(0x40, add(array2, 0x40))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Interface that must be implemented by smart contracts in order to receive
 * ERC-1155 token transfers.
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

/*
 SPDX-License-Identifier: MIT
*/

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {AppStorage, LibAppStorage} from "./LibAppStorage.sol";
import {LibRedundantMath128} from "./LibRedundantMath128.sol";
import {C} from "../C.sol";
import {LibUnripe} from "./LibUnripe.sol";
import {IWell} from "contracts/interfaces/basin/IWell.sol";
import {LibBarnRaise} from "./LibBarnRaise.sol";
import {LibDiamond} from "contracts/libraries/LibDiamond.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {LibWell} from "contracts/libraries/Well/LibWell.sol";
import {LibUsdOracle} from "contracts/libraries/Oracle/LibUsdOracle.sol";
import {LibTractor} from "contracts/libraries/LibTractor.sol";
import {BeanstalkERC20} from "contracts/tokens/ERC20/BeanstalkERC20.sol";

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

library LibFertilizer {
    using LibRedundantMath256 for uint256;
    using LibRedundantMath128 for uint128;
    using SafeCast for uint256;
    using SafeERC20 for IERC20;
    using LibWell for address;

    event SetFertilizer(uint128 id, uint128 bpf);

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

    /**
     * @dev Adds a new fertilizer to Beanstalk, updates global state,
     * the season queue, and returns the corresponding fertilizer id.
     * @param season The season the fertilizer is added.
     * @param tokenAmountIn The amount of barnRaiseToken being used to purchase Fertilizer.
     * @param fertilizerAmount The amount of Fertilizer to add.
     * @param minLP The minimum amount of LP to add.
     * @return id The id of the Fertilizer.
     */
    function addFertilizer(
        uint128 season,
        uint256 tokenAmountIn,
        uint256 fertilizerAmount,
        uint256 minLP
    ) internal returns (uint128 id) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        uint128 fertilizerAmount128 = fertilizerAmount.toUint128();

        // Calculate Beans Per Fertilizer and add to total owed
        uint128 bpf = getBpf(season);
        s.sys.fert.unfertilizedIndex = s.sys.fert.unfertilizedIndex.add(fertilizerAmount.mul(bpf));
        // Get id
        id = s.sys.fert.bpf.add(bpf);
        // Update Total and Season supply
        s.sys.fert.fertilizer[id] = s.sys.fert.fertilizer[id].add(fertilizerAmount128);
        s.sys.fert.activeFertilizer = s.sys.fert.activeFertilizer.add(fertilizerAmount);
        // Add underlying to Unripe Beans and Unripe LP
        addUnderlying(tokenAmountIn, fertilizerAmount.mul(DECIMALS), minLP);
        // If not first time adding Fertilizer with this id, return
        if (s.sys.fert.fertilizer[id] > fertilizerAmount128) return id;
        // If first time, log end Beans Per Fertilizer and add to Season queue.
        push(id);
        emit SetFertilizer(id, bpf);
    }

    /**
     * @dev Calculates the Beans Per Fertilizer for a given season.
     * Forluma is bpf = Humidity + 1000 * 1,000
     * @param id The id of the Fertilizer.
     * @return bpf The Beans Per Fertilizer.
     */
    function getBpf(uint128 id) internal pure returns (uint128 bpf) {
        bpf = getHumidity(id).add(1000).mul(PADDING);
    }

    /**
     * @dev Calculates the Humidity for a given season.
     * The Humidity was 500% prior to Replant, after which it dropped to 250% (Season 6074)
     * and then decreased by an additional 0.5% each Season until it reached 20%.
     * The Humidity will remain at 20% until all Available Fertilizer is purchased.
     * @param id The season.
     * @return humidity The corresponding Humidity.
     */
    function getHumidity(uint128 id) internal pure returns (uint128 humidity) {
        if (id == 0) return 5000;
        if (id >= END_DECREASE_SEASON) return 200;
        uint128 humidityDecrease = id.sub(REPLANT_SEASON).mul(5);
        humidity = RESTART_HUMIDITY.sub(humidityDecrease);
    }

    /**
     * @dev Transfers `tokenAmountIn` of `barnRaiseToken` to the Barn Raise Well, mints and
     * adds corresponding Bean liquidity.
     */
    function addUnderlying(
        uint256 tokenAmountIn,
        uint256 usdAmount,
        uint256 minAmountOut
    ) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        // Calculate how many new Deposited Beans will be minted
        uint256 percentToFill = usdAmount.mul(C.precision()).div(remainingRecapitalization());

        uint256 newDepositedBeans;
        if (
            IERC20(s.sys.tokens.urBean).totalSupply() >
            s.sys.silo.unripeSettings[s.sys.tokens.urBean].balanceOfUnderlying
        ) {
            newDepositedBeans = (IERC20(s.sys.tokens.urBean).totalSupply()).sub(
                s.sys.silo.unripeSettings[s.sys.tokens.urBean].balanceOfUnderlying
            );
            newDepositedBeans = newDepositedBeans.mul(percentToFill).div(C.precision());
        }
        // Calculate how many Beans to add as LP
        uint256 newDepositedLPBeans = usdAmount.mul(C.exploitAddLPRatio()).div(DECIMALS);

        // Mint the Deposited Beans to Beanstalk.
        BeanstalkERC20(s.sys.tokens.bean).mint(address(this), newDepositedBeans);

        // Mint the LP Beans and add liquidity to the well.
        address barnRaiseWell = LibBarnRaise.getBarnRaiseWell();
        address barnRaiseToken = LibBarnRaise.getBarnRaiseToken();

        BeanstalkERC20(s.sys.tokens.bean).mint(address(this), newDepositedLPBeans);

        IERC20(barnRaiseToken).transferFrom(
            LibTractor._user(),
            address(this),
            uint256(tokenAmountIn)
        );

        IERC20(barnRaiseToken).approve(barnRaiseWell, uint256(tokenAmountIn));
        BeanstalkERC20(s.sys.tokens.bean).approve(barnRaiseWell, newDepositedLPBeans);

        uint256[] memory tokenAmountsIn = new uint256[](2);
        IERC20[] memory tokens = IWell(barnRaiseWell).tokens();
        (tokenAmountsIn[0], tokenAmountsIn[1]) = tokens[0] == BeanstalkERC20(s.sys.tokens.bean)
            ? (newDepositedLPBeans, tokenAmountIn)
            : (tokenAmountIn, newDepositedLPBeans);

        uint256 newLP = IWell(barnRaiseWell).addLiquidity(
            tokenAmountsIn,
            minAmountOut,
            address(this),
            type(uint256).max
        );

        // Increment underlying balances of Unripe Tokens
        LibUnripe.incrementUnderlying(s.sys.tokens.urBean, newDepositedBeans);
        LibUnripe.incrementUnderlying(s.sys.tokens.urLp, newLP);

        s.sys.fert.recapitalized = s.sys.fert.recapitalized.add(usdAmount);
    }

    /**
     * @dev Adds a fertilizer id in the queue.
     * fFirst is the lowest active Fertilizer Id (see AppStorage)
     * (start of linked list that is stored by nextFid).
     *  The highest active Fertilizer Id
     * (end of linked list that is stored by nextFid).
     * @param id The id of the fertilizer.
     */
    function push(uint128 id) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (s.sys.fert.fertFirst == 0) {
            // Queue is empty
            s.sys.season.fertilizing = true;
            s.sys.fert.fertLast = id;
            s.sys.fert.fertFirst = id;
        } else if (id <= s.sys.fert.fertFirst) {
            // Add to front of queue
            setNext(id, s.sys.fert.fertFirst);
            s.sys.fert.fertFirst = id;
        } else if (id >= s.sys.fert.fertLast) {
            // Add to back of queue
            setNext(s.sys.fert.fertLast, id);
            s.sys.fert.fertLast = id;
        } else {
            // Add to middle of queue
            uint128 prev = s.sys.fert.fertFirst;
            uint128 next = getNext(prev);
            // Search for proper place in line
            while (id > next) {
                prev = next;
                next = getNext(next);
            }
            setNext(prev, id);
            setNext(id, next);
        }
    }

    /**
     * @dev Returns the dollar amount remaining for beanstalk to recapitalize.
     * @return remaining The dollar amount remaining.
     */
    function remainingRecapitalization() internal view returns (uint256 remaining) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 totalDollars = getTotalRecapDollarsNeeded();
        if (s.sys.fert.recapitalized >= totalDollars) return 0;
        return totalDollars.sub(s.sys.fert.recapitalized);
    }

    /**
     * @dev Returns the total dollar amount needed to recapitalize Beanstalk.
     * @return totalDollars The total dollar amount.
     */
    function getTotalRecapDollarsNeeded() internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return getTotalRecapDollarsNeeded(IERC20(s.sys.tokens.urLp).totalSupply());
    }

    /**
     * @dev Returns the total dollar amount needed to recapitalize Beanstalk
     * for the supply of Unripe LP.
     * @param urLPsupply The supply of Unripe LP.
     * @return totalDollars The total dollar amount.
     */
    function getTotalRecapDollarsNeeded(uint256 urLPsupply) internal pure returns (uint256) {
        uint256 totalDollars = C.dollarPerUnripeLP().mul(urLPsupply).div(DECIMALS);
        totalDollars = (totalDollars / 1e6) * 1e6; // round down to nearest USDC
        return totalDollars;
    }

    /**
     * @dev Removes the first fertilizer id in the queue.
     * fFirst is the lowest active Fertilizer Id (see AppStorage)
     * (start of linked list that is stored by nextFid).
     * @return bool Whether the queue is empty.
     */
    function pop() internal returns (bool) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint128 first = s.sys.fert.fertFirst;
        s.sys.fert.activeFertilizer = s.sys.fert.activeFertilizer.sub(getAmount(first));
        uint128 next = getNext(first);
        if (next == 0) {
            // If all Unfertilized Beans have been fertilized, delete line.
            require(s.sys.fert.activeFertilizer == 0, "Still active fertilizer");
            s.sys.fert.fertFirst = 0;
            s.sys.fert.fertLast = 0;
            s.sys.season.fertilizing = false;
            return false;
        }
        s.sys.fert.fertFirst = getNext(first);
        return true;
    }

    /**
     * @dev Returns the amount (supply) of fertilizer for a given id.
     * @param id The id of the fertilizer.
     */
    function getAmount(uint128 id) internal view returns (uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.fert.fertilizer[id];
    }

    /**
     * @dev Returns the next fertilizer id in the list given a fertilizer id.
     * nextFid is a linked list of Fertilizer Ids ordered by Id number. (See AppStorage)
     * @param id The id of the fertilizer.
     */
    function getNext(uint128 id) internal view returns (uint128) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.fert.nextFid[id];
    }

    /**
     * @dev Sets the next fertilizer id in the list given a fertilizer id.
     * nextFid is a linked list of Fertilizer Ids ordered by Id number. (See AppStorage)
     * @param id The id of the fertilizer.
     * @param next The id of the next fertilizer.
     */
    function setNext(uint128 id, uint128 next) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.sys.fert.nextFid[id] = next;
    }

    function beginBarnRaiseMigration(address well) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        require(well.isWell(), "Fertilizer: Not a Whitelisted Well.");

        // The Barn Raise only supports 2 token Wells where 1 token is Bean and the
        // other is supported by the Lib Usd Oracle.
        IERC20[] memory tokens = IWell(well).tokens();
        require(tokens.length == 2, "Fertilizer: Well must have 2 tokens.");
        require(
            tokens[0] == BeanstalkERC20(s.sys.tokens.bean) ||
                tokens[1] == BeanstalkERC20(s.sys.tokens.bean),
            "Fertilizer: Well must have BEAN."
        );
        // Check that Lib Usd Oracle supports the non-Bean token in the Well.
        require(
            LibUsdOracle.getTokenPrice(
                address(tokens[tokens[0] == BeanstalkERC20(s.sys.tokens.bean) ? 1 : 0])
            ) != 0
        );

        uint256 balanceOfUnderlying = s
            .sys
            .silo
            .unripeSettings[s.sys.tokens.urLp]
            .balanceOfUnderlying;
        IERC20(s.sys.silo.unripeSettings[s.sys.tokens.urLp].underlyingToken).safeTransfer(
            LibDiamond.diamondStorage().contractOwner,
            balanceOfUnderlying
        );
        LibUnripe.decrementUnderlying(s.sys.tokens.urLp, balanceOfUnderlying);
        LibUnripe.switchUnderlyingToken(s.sys.tokens.urLp, well);
    }

    /**
     * Taken from previous versions of OpenZeppelin Library.
     * @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;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

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

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the value of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155Received} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `value` amount.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * WARNING: This function can potentially allow a reentrancy attack when transferring tokens
     * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
     * Ensure to follow the checks-effects-interactions pattern and consider employing
     * reentrancy guards when interacting with untrusted contracts.
     *
     * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
     *
     * Requirements:
     *
     * - `ids` and `values` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165Upgradeable is Initializable, IERC165 {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";

/**
 * @dev Collection of functions related to array types.
 */
library Arrays {
    using StorageSlot for bytes32;

    /**
     * @dev Searches a sorted `array` and returns the first index that contains
     * a value greater or equal to `element`. If no such index exists (i.e. all
     * values in the array are strictly less than `element`), the array length is
     * returned. Time complexity O(log n).
     *
     * `array` is expected to be sorted in ascending order, and to contain no
     * repeated elements.
     */
    function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
        uint256 low = 0;
        uint256 high = array.length;

        if (high == 0) {
            return 0;
        }

        while (low < high) {
            uint256 mid = Math.average(low, high);

            // Note that mid will always be strictly less than high (i.e. it will be a valid array index)
            // because Math.average rounds towards zero (it does integer division with truncation).
            if (unsafeAccess(array, mid).value > element) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
        if (low > 0 && unsafeAccess(array, low - 1).value == element) {
            return low - 1;
        } else {
            return low;
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getAddressSlot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getBytes32Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
        bytes32 slot;
        // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
        // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.

        /// @solidity memory-safe-assembly
        assembly {
            mstore(0, arr.slot)
            slot := add(keccak256(0, 0x20), pos)
        }
        return slot.getUint256Slot();
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }

    /**
     * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
     *
     * WARNING: Only use if you are certain `pos` is lower than the array length.
     */
    function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
        assembly {
            res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 25 of 82 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @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.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @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) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(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) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(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) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(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) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        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) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        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) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, 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
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, 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
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, 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
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, 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
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, 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
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, 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) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

File 26 of 82 : LibAppStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

// Import all of AppStorage to give importers of LibAppStorage access to {Account}, etc.
import {AppStorage} from "../beanstalk/storage/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
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

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

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

    uint256 internal constant PRECISION = 1e18;

    //////////////////// Reentrancy ////////////////////
    uint256 internal constant NOT_ENTERED = 1;
    uint256 internal constant ENTERED = 2;

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

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

    //////////////////// Silo ////////////////////
    uint256 internal constant STALK_PER_BEAN = 1e10;
    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;

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

    address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address internal constant PIPELINE = 0xb1bE000644bD25996b0d9C2F7a6D6BA3954c91B0;

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

    uint256 internal constant WELL_MINIMUM_BEAN_BALANCE = 1000_000_000; // 1,000 Beans

    //////////////////// Tractor ////////////////////

    uint80 internal constant SLOT_SIZE = 32;
    // Special index to indicate the data to copy is the publisher address.
    uint80 internal constant PUBLISHER_COPY_INDEX = type(uint80).max;
    // Special index to indicate the data to copy is the operator address.
    uint80 internal constant OPERATOR_COPY_INDEX = type(uint80).max - 1;

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

    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 pipeline() internal pure returns (IPipeline) {
        return IPipeline(PIPELINE);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {IBean} from "../interfaces/IBean.sol";
import {AppStorage, LibAppStorage} from "./LibAppStorage.sol";
import {C} from "../C.sol";
import {LibWell} from "./Well/LibWell.sol";
import {Call, IWell} from "contracts/interfaces/basin/IWell.sol";
import {IWellFunction} from "contracts/interfaces/basin/IWellFunction.sol";
import {LibLockedUnderlying} from "./LibLockedUnderlying.sol";
import {LibFertilizer} from "./LibFertilizer.sol";

/**
 * @title LibUnripe
 * @author Publius
 * @notice Library for handling functionality related to Unripe Tokens and their Ripe Tokens.
 */
library LibUnripe {
    using LibRedundantMath256 for uint256;

    event ChangeUnderlying(address indexed token, int256 underlying);
    event SwitchUnderlyingToken(address indexed token, address indexed underlyingToken);

    uint256 constant DECIMALS = 1e6;

    /**
     * @notice Returns the percentage that Unripe Beans have been recapitalized.
     */
    function percentBeansRecapped() internal view returns (uint256 percent) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return
            s.sys.silo.unripeSettings[s.sys.tokens.urBean].balanceOfUnderlying.mul(DECIMALS).div(
                IERC20(s.sys.tokens.urBean).totalSupply()
            );
    }

    /**
     * @notice Returns the percentage that Unripe LP have been recapitalized.
     */
    function percentLPRecapped() internal view returns (uint256 percent) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return
            C.unripeLPPerDollar().mul(s.sys.fert.recapitalized).div(
                IERC20(s.sys.tokens.urLp).totalSupply()
            );
    }

    /**
     * @notice Increments the underlying balance of an Unripe Token.
     * @param token The address of the unripe token.
     * @param amount The amount of the of the unripe token to be added to the storage reserves
     */
    function incrementUnderlying(address token, uint256 amount) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.sys.silo.unripeSettings[token].balanceOfUnderlying = s
            .sys
            .silo
            .unripeSettings[token]
            .balanceOfUnderlying
            .add(amount);
        emit ChangeUnderlying(token, int256(amount));
    }

    /**
     * @notice Decrements the underlying balance of an Unripe Token.
     * @param token The address of the Unripe Token.
     * @param amount The amount of the of the Unripe Token to be removed from storage reserves
     */
    function decrementUnderlying(address token, uint256 amount) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.sys.silo.unripeSettings[token].balanceOfUnderlying = s
            .sys
            .silo
            .unripeSettings[token]
            .balanceOfUnderlying
            .sub(amount);
        emit ChangeUnderlying(token, -int256(amount));
    }

    /**
     * @notice Calculates the amount of Ripe Tokens that underly a given amount of Unripe Tokens.
     * @param unripeToken The address of the Unripe Token
     * @param unripe The amount of Unripe Tokens.
     * @return underlying The amount of Ripe Tokens that underly the Unripe Tokens.
     */
    function unripeToUnderlying(
        address unripeToken,
        uint256 unripe,
        uint256 supply
    ) internal view returns (uint256 underlying) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        underlying = s.sys.silo.unripeSettings[unripeToken].balanceOfUnderlying.mul(unripe).div(
            supply
        );
    }

    /**
     * @notice Calculates the amount of Unripe Tokens that are underlaid by a given amount of Ripe Tokens.
     * @param unripeToken The address of the Unripe Tokens.
     * @param underlying The amount of Ripe Tokens.
     * @return unripe The amount of the of the Unripe Tokens that are underlaid by the Ripe Tokens.
     */
    function underlyingToUnripe(
        address unripeToken,
        uint256 underlying
    ) internal view returns (uint256 unripe) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        unripe = IBean(unripeToken).totalSupply().mul(underlying).div(
            s.sys.silo.unripeSettings[unripeToken].balanceOfUnderlying
        );
    }

    /**
     * @notice Adds Ripe Tokens to an Unripe Token. Also, increments the recapitalized
     * amount proportionally if the Unripe Token is Unripe LP.
     * @param token The address of the Unripe Token to add Ripe Tokens to.
     * @param underlying The amount of the of the underlying token to be taken as input.
     */
    function addUnderlying(address token, uint256 underlying) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (token == s.sys.tokens.urLp) {
            uint256 recapped = underlying.mul(s.sys.fert.recapitalized).div(
                s.sys.silo.unripeSettings[s.sys.tokens.urLp].balanceOfUnderlying
            );
            s.sys.fert.recapitalized = s.sys.fert.recapitalized.add(recapped);
        }
        incrementUnderlying(token, underlying);
    }

    /**
     * @notice Removes Ripe Tokens from an Unripe Token. Also, decrements the recapitalized
     * amount proportionally if the Unripe Token is Unripe LP.
     * @param token The address of the unripe token to be removed.
     * @param underlying The amount of the of the underlying token to be removed.
     */
    function removeUnderlying(address token, uint256 underlying) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        if (token == s.sys.tokens.urLp) {
            uint256 recapped = underlying.mul(s.sys.fert.recapitalized).div(
                s.sys.silo.unripeSettings[s.sys.tokens.urLp].balanceOfUnderlying
            );
            s.sys.fert.recapitalized = s.sys.fert.recapitalized.sub(recapped);
        }
        decrementUnderlying(token, underlying);
    }

    /**
     * @dev Switches the underlying token of an unripe token.
     * Should only be called if `s.silo.unripeSettings[unripeToken].balanceOfUnderlying == 0`.
     */
    function switchUnderlyingToken(address unripeToken, address newUnderlyingToken) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.sys.silo.unripeSettings[unripeToken].underlyingToken = newUnderlyingToken;
        emit SwitchUnderlyingToken(unripeToken, newUnderlyingToken);
    }

    /**
     * @notice Calculates the the penalized amount of Ripe Tokens corresponding to
     * the amount of Unripe Tokens that are Chopped according to the current Chop Rate.
     * The new chop rate is %Recapitalized^2.
     */
    function getPenalizedUnderlying(
        address unripeToken,
        uint256 amount,
        uint256 supply
    ) internal view returns (uint256 redeem) {
        require(isUnripe(unripeToken), "not vesting");
        AppStorage storage s = LibAppStorage.diamondStorage();
        // getTotalRecapDollarsNeeded() queries for the total urLP supply which is burned upon a chop
        // If the token being chopped is unripeLP, getting the current supply here is inaccurate due to the burn
        // Instead, we use the supply passed in as an argument to getTotalRecapDollarsNeeded since the supply variable
        // here is the total urToken supply queried before burnning the unripe token
        uint256 totalUsdNeeded = unripeToken == s.sys.tokens.urLp
            ? LibFertilizer.getTotalRecapDollarsNeeded(supply)
            : LibFertilizer.getTotalRecapDollarsNeeded();
        // chop rate = total redeemable * (%DollarRecapitalized)^2 * share of unripe tokens
        // redeem = totalRipeUnderlying * (usdValueRaised/totalUsdNeeded)^2 * UnripeAmountIn/UnripeSupply;
        // But totalRipeUnderlying = CurrentUnderlying * totalUsdNeeded/usdValueRaised to get the total underlying
        // redeem = currentRipeUnderlying * (usdValueRaised/totalUsdNeeded) * UnripeAmountIn/UnripeSupply
        uint256 underlyingAmount = s.sys.silo.unripeSettings[unripeToken].balanceOfUnderlying;
        if (totalUsdNeeded == 0) {
            // when totalUsdNeeded == 0, the barnraise has been fully recapitalized.
            redeem = underlyingAmount.mul(amount).div(supply);
        } else {
            redeem = underlyingAmount
                .mul(s.sys.fert.recapitalized)
                .div(totalUsdNeeded)
                .mul(amount)
                .div(supply);
        }

        // cap `redeem to `balanceOfUnderlying in the case that `s.recapitalized` exceeds `totalUsdNeeded`.
        // this can occur due to unripe LP chops.
        if (redeem > underlyingAmount) redeem = underlyingAmount;
    }

    /**
     * @notice returns the total percentage that beanstalk has recapitalized.
     * @dev this is calculated by the ratio of s.recapitalized and the total dollars the barnraise needs to raise.
     * returns the same precision as `getRecapPaidPercentAmount` (100% recapitalized = 1e6).
     */
    function getTotalRecapitalizedPercent() internal view returns (uint256 recapitalizedPercent) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        uint256 totalUsdNeeded = LibFertilizer.getTotalRecapDollarsNeeded();
        if (totalUsdNeeded == 0) {
            return 1e6; // if zero usd needed, full recap has happened
        }
        return s.sys.fert.recapitalized.mul(DECIMALS).div(totalUsdNeeded);
    }

    /**
     * @notice Returns the amount of beans that are locked in the unripe token.
     * @dev Locked beans are the beans that are forfeited if the unripe token is chopped.
     * @param reserves the reserves of the LP that underly the unripe token.
     * @dev reserves are used as a parameter for gas effiency purposes (see LibEvaluate.calcLPToSupplyRatio}.
     */
    function getLockedBeans(
        uint256[] memory reserves
    ) internal view returns (uint256 lockedAmount) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        lockedAmount = LibLockedUnderlying
            .getLockedUnderlying(s.sys.tokens.urBean, getTotalRecapitalizedPercent())
            .add(getLockedBeansFromLP(reserves));
    }

    /**
     * @notice Returns the amount of beans that are locked in the unripeLP token.
     * @param reserves the reserves of the LP that underly the unripe token.
     */
    function getLockedBeansFromLP(
        uint256[] memory reserves
    ) internal view returns (uint256 lockedBeanAmount) {
        AppStorage storage s = LibAppStorage.diamondStorage();

        // if reserves return 0, then skip calculations.
        if (reserves[0] == 0) return 0;
        uint256 lockedLpAmount = LibLockedUnderlying.getLockedUnderlying(
            s.sys.tokens.urLp,
            getTotalRecapitalizedPercent()
        );
        address underlying = s.sys.silo.unripeSettings[s.sys.tokens.urLp].underlyingToken;
        uint256 beanIndex = LibWell.getBeanIndexFromWell(underlying);

        // lpTokenSupply is calculated rather than calling totalSupply(),
        // because the Well's lpTokenSupply is not MEV resistant.
        Call memory wellFunction = IWell(underlying).wellFunction();
        uint lpTokenSupply = IWellFunction(wellFunction.target).calcLpTokenSupply(
            reserves,
            wellFunction.data
        );
        lockedBeanAmount = lockedLpAmount.mul(reserves[beanIndex]).div(lpTokenSupply);
    }

    /**
     * @notice Calculates the penalized amount based the amount of Sprouts that are Rinsable
     * or Rinsed (Fertilized).
     * @param amount The amount of the Unripe Tokens.
     * @return penalizedAmount The penalized amount of the Ripe Tokens received from Chopping.
     */
    function getRecapPaidPercentAmount(
        uint256 amount
    ) internal view returns (uint256 penalizedAmount) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.fert.fertilizedIndex.mul(amount).div(s.sys.fert.unfertilizedIndex);
    }

    /**
     * @notice Returns true if the token is unripe.
     */
    function isUnripe(address unripeToken) internal view returns (bool unripe) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        unripe = s.sys.silo.unripeSettings[unripeToken].underlyingToken != address(0);
    }

    /**
     * @notice Returns the underlying token amount of the unripe token.
     */
    function _getUnderlying(
        address unripeToken,
        uint256 amount,
        uint256 supply
    ) internal view returns (uint256 redeem) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        redeem = s.sys.silo.unripeSettings[unripeToken].balanceOfUnderlying.mul(amount).div(supply);
    }

    function _getUnderlyingToken(
        address unripeToken
    ) internal view returns (address underlyingToken) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.silo.unripeSettings[unripeToken].underlyingToken;
    }

    function getTotalRecapDollarsNeeded() internal view returns (uint256 totalUsdNeeded) {
        return LibFertilizer.getTotalRecapDollarsNeeded();
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

/**
 * @title Call is the struct that contains the target address and extra calldata of a generic call.
 */
struct Call {
    address target; // The address the call is executed on.
    bytes data; // Extra calldata to be passed during the call
}

/**
 * @title IWell is the interface for the Well contract.
 *
 * In order for a Well to be verified using a permissionless on-chain registry, a Well Implementation should:
 * - Not be able to self-destruct (Aquifer's registry would be vulnerable to a metamorphic contract attack)
 * - Not be able to change its tokens, Well Function, Pumps and Well Data
 */
interface IWell {
    /**
     * @notice Emitted when a Swap occurs.
     * @param fromToken The token swapped from
     * @param toToken The token swapped to
     * @param amountIn The amount of `fromToken` transferred into the Well
     * @param amountOut The amount of `toToken` transferred out of the Well
     * @param recipient The address that received `toToken`
     */
    event Swap(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amountIn,
        uint256 amountOut,
        address recipient
    );

    /**
     * @notice Emitted when liquidity is added to the Well.
     * @param tokenAmountsIn The amount of each token added to the Well
     * @param lpAmountOut The amount of LP tokens minted
     * @param recipient The address that received the LP tokens
     */
    event AddLiquidity(uint256[] tokenAmountsIn, uint256 lpAmountOut, address recipient);

    /**
     * @notice Emitted when liquidity is removed from the Well as multiple underlying tokens.
     * @param lpAmountIn The amount of LP tokens burned
     * @param tokenAmountsOut The amount of each underlying token removed
     * @param recipient The address that received the underlying tokens
     * @dev Gas cost scales with `n` tokens.
     */
    event RemoveLiquidity(uint256 lpAmountIn, uint256[] tokenAmountsOut, address recipient);

    /**
     * @notice Emitted when liquidity is removed from the Well as a single underlying token.
     * @param lpAmountIn The amount of LP tokens burned
     * @param tokenOut The underlying token removed
     * @param tokenAmountOut The amount of `tokenOut` removed
     * @param recipient The address that received the underlying tokens
     * @dev Emitting a separate event when removing liquidity as a single token
     * saves gas, since `tokenAmountsOut` in {RemoveLiquidity} must emit a value
     * for each token in the Well.
     */
    event RemoveLiquidityOneToken(
        uint256 lpAmountIn,
        IERC20 tokenOut,
        uint256 tokenAmountOut,
        address recipient
    );

    /**
     * @notice Emitted when a Shift occurs.
     * @param reserves The ending reserves after a shift
     * @param toToken The token swapped to
     * @param amountOut The amount of `toToken` transferred out of the Well
     * @param recipient The address that received `toToken`
     */
    event Shift(uint256[] reserves, IERC20 toToken, uint256 amountOut, address recipient);

    /**
     * @notice Emitted when a Sync occurs.
     * @param reserves The ending reserves after a sync
     * @param lpAmountOut The amount of LP tokens received from the sync.
     * @param recipient The address that received the LP tokens
     */
    event Sync(uint256[] reserves, uint256 lpAmountOut, address recipient);

    //////////////////// WELL DEFINITION ////////////////////

    /**
     * @notice Returns a list of ERC20 tokens supported by the Well.
     */
    function tokens() external view returns (IERC20[] memory);

    /**
     * @notice Returns the Well function as a Call struct.
     * @dev Contains the address of the Well function contract and extra data to
     * pass during calls.
     *
     * **Well functions** define a relationship between the reserves of the
     * tokens in the Well and the number of LP tokens.
     *
     * A Well function MUST implement {IWellFunction}.
     */
    function wellFunction() external view returns (Call memory);

    /**
     * @notice Returns the Pumps attached to the Well as Call structs.
     * @dev Contains the addresses of the Pumps contract and extra data to pass
     * during calls.
     *
     * **Pumps** are on-chain oracles that are updated every time the Well is
     * interacted with.
     *
     * A Pump is not required for Well operation. For Wells without a Pump:
     * `pumps().length = 0`.
     *
     * An attached Pump MUST implement {IPump}.
     */
    function pumps() external view returns (Call[] memory);

    /**
     * @notice Returns the Well data that the Well was bored with.
     * @dev The existence and signature of Well data is determined by each individual implementation.
     */
    function wellData() external view returns (bytes memory);

    /**
     * @notice Returns the Aquifer that created this Well.
     * @dev Wells can be permissionlessly bored in an Aquifer.
     *
     * Aquifers stores the implementation that was used to bore the Well.
     */
    function aquifer() external view returns (address);

    /**
     * @notice Returns the tokens, Well Function, Pumps and Well Data associated
     * with the Well as well as the Aquifer that deployed the Well.
     */
    function well()
        external
        view
        returns (
            IERC20[] memory _tokens,
            Call memory _wellFunction,
            Call[] memory _pumps,
            bytes memory _wellData,
            address _aquifer
        );

    //////////////////// SWAP: FROM ////////////////////

    /**
     * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken`.
     * @param fromToken The token to swap from
     * @param toToken The token to swap to
     * @param amountIn The amount of `fromToken` to spend
     * @param minAmountOut The minimum amount of `toToken` to receive
     * @param recipient The address to receive `toToken`
     * @param deadline The timestamp after which this operation is invalid
     * @return amountOut The amount of `toToken` received
     */
    function swapFrom(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amountIn,
        uint256 minAmountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 amountOut);

    /**
     * @notice Swaps from an exact amount of `fromToken` to a minimum amount of `toToken` and supports fee on transfer tokens.
     * @param fromToken The token to swap from
     * @param toToken The token to swap to
     * @param amountIn The amount of `fromToken` to spend
     * @param minAmountOut The minimum amount of `toToken` to take from the Well. Note that if `toToken` charges a fee on transfer, `recipient` will receive less than this amount.
     * @param recipient The address to receive `toToken`
     * @param deadline The timestamp after which this operation is invalid
     * @return amountOut The amount of `toToken` transferred from the Well. Note that if `toToken` charges a fee on transfer, `recipient` may receive less than this amount.
     * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient.
     */
    function swapFromFeeOnTransfer(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amountIn,
        uint256 minAmountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 amountOut);

    /**
     * @notice Gets the amount of one token received for swapping an amount of another token.
     * @param fromToken The token to swap from
     * @param toToken The token to swap to
     * @param amountIn The amount of `fromToken` to spend
     * @return amountOut The amount of `toToken` to receive
     */
    function getSwapOut(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amountIn
    ) external view returns (uint256 amountOut);

    //////////////////// SWAP: TO ////////////////////

    /**
     * @notice Swaps from a maximum amount of `fromToken` to an exact amount of `toToken`.
     * @param fromToken The token to swap from
     * @param toToken The token to swap to
     * @param maxAmountIn The maximum amount of `fromToken` to spend
     * @param amountOut The amount of `toToken` to receive
     * @param recipient The address to receive `toToken`
     * @param deadline The timestamp after which this operation is invalid
     * @return amountIn The amount of `toToken` received
     */
    function swapTo(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 maxAmountIn,
        uint256 amountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 amountIn);

    /**
     * @notice Gets the amount of one token that must be spent to receive an amount of another token during a swap.
     * @param fromToken The token to swap from
     * @param toToken The token to swap to
     * @param amountOut The amount of `toToken` desired
     * @return amountIn The amount of `fromToken` that must be spent
     */
    function getSwapIn(
        IERC20 fromToken,
        IERC20 toToken,
        uint256 amountOut
    ) external view returns (uint256 amountIn);

    //////////////////// SHIFT ////////////////////

    /**
     * @notice Shifts at least `minAmountOut` excess tokens held by the Well into `tokenOut` and delivers to `recipient`.
     * @param tokenOut The token to shift into
     * @param minAmountOut The minimum amount of `tokenOut` to receive
     * @param recipient The address to receive the token
     * @return amountOut The amount of `tokenOut` received
     * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient swaps.
     * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall,
     * then a deadline check can be added to the multicall.
     */
    function shift(
        IERC20 tokenOut,
        uint256 minAmountOut,
        address recipient
    ) external returns (uint256 amountOut);

    /**
     * @notice Calculates the amount of the token out received from shifting excess tokens held by the Well.
     * @param tokenOut The token to shift into
     * @return amountOut The amount of `tokenOut` received
     */
    function getShiftOut(IERC20 tokenOut) external returns (uint256 amountOut);

    //////////////////// ADD LIQUIDITY ////////////////////

    /**
     * @notice Adds liquidity to the Well as multiple tokens in any ratio.
     * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
     * @param minLpAmountOut The minimum amount of LP tokens to receive
     * @param recipient The address to receive the LP tokens
     * @param deadline The timestamp after which this operation is invalid
     * @return lpAmountOut The amount of LP tokens received
     */
    function addLiquidity(
        uint256[] memory tokenAmountsIn,
        uint256 minLpAmountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 lpAmountOut);

    /**
     * @notice Adds liquidity to the Well as multiple tokens in any ratio and supports
     * fee on transfer tokens.
     * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
     * @param minLpAmountOut The minimum amount of LP tokens to receive
     * @param recipient The address to receive the LP tokens
     * @param deadline The timestamp after which this operation is invalid
     * @return lpAmountOut The amount of LP tokens received
     * @dev Can also be used for tokens without a fee on transfer, but is less gas efficient.
     */
    function addLiquidityFeeOnTransfer(
        uint256[] memory tokenAmountsIn,
        uint256 minLpAmountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 lpAmountOut);

    /**
     * @notice Gets the amount of LP tokens received from adding liquidity as multiple tokens in any ratio.
     * @param tokenAmountsIn The amount of each token to add; MUST match the indexing of {Well.tokens}
     * @return lpAmountOut The amount of LP tokens received
     */
    function getAddLiquidityOut(
        uint256[] memory tokenAmountsIn
    ) external view returns (uint256 lpAmountOut);

    //////////////////// REMOVE LIQUIDITY: BALANCED ////////////////////

    /**
     * @notice Removes liquidity from the Well as all underlying tokens in a balanced ratio.
     * @param lpAmountIn The amount of LP tokens to burn
     * @param minTokenAmountsOut The minimum amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
     * @param recipient The address to receive the underlying tokens
     * @param deadline The timestamp after which this operation is invalid
     * @return tokenAmountsOut The amount of each underlying token received
     */
    function removeLiquidity(
        uint256 lpAmountIn,
        uint256[] calldata minTokenAmountsOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256[] memory tokenAmountsOut);

    /**
     * @notice Gets the amount of each underlying token received from removing liquidity in a balanced ratio.
     * @param lpAmountIn The amount of LP tokens to burn
     * @return tokenAmountsOut The amount of each underlying token received
     */
    function getRemoveLiquidityOut(
        uint256 lpAmountIn
    ) external view returns (uint256[] memory tokenAmountsOut);

    //////////////////// REMOVE LIQUIDITY: ONE TOKEN ////////////////////

    /**
     * @notice Removes liquidity from the Well as a single underlying token.
     * @param lpAmountIn The amount of LP tokens to burn
     * @param tokenOut The underlying token to receive
     * @param minTokenAmountOut The minimum amount of `tokenOut` to receive
     * @param recipient The address to receive the underlying tokens
     * @param deadline The timestamp after which this operation is invalid
     * @return tokenAmountOut The amount of `tokenOut` received
     */
    function removeLiquidityOneToken(
        uint256 lpAmountIn,
        IERC20 tokenOut,
        uint256 minTokenAmountOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 tokenAmountOut);

    /**
     * @notice Gets the amount received from removing liquidity from the Well as a single underlying token.
     * @param lpAmountIn The amount of LP tokens to burn
     * @param tokenOut The underlying token to receive
     * @return tokenAmountOut The amount of `tokenOut` received
     *
     */
    function getRemoveLiquidityOneTokenOut(
        uint256 lpAmountIn,
        IERC20 tokenOut
    ) external view returns (uint256 tokenAmountOut);

    //////////////////// REMOVE LIQUIDITY: IMBALANCED ////////////////////

    /**
     * @notice Removes liquidity from the Well as multiple underlying tokens in any ratio.
     * @param maxLpAmountIn The maximum amount of LP tokens to burn
     * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
     * @param recipient The address to receive the underlying tokens
     * @return lpAmountIn The amount of LP tokens burned
     */
    function removeLiquidityImbalanced(
        uint256 maxLpAmountIn,
        uint256[] calldata tokenAmountsOut,
        address recipient,
        uint256 deadline
    ) external returns (uint256 lpAmountIn);

    /**
     * @notice Gets the amount of LP tokens to burn from removing liquidity as multiple underlying tokens in any ratio.
     * @param tokenAmountsOut The amount of each underlying token to receive; MUST match the indexing of {Well.tokens}
     * @return lpAmountIn The amount of LP tokens burned
     */
    function getRemoveLiquidityImbalancedIn(
        uint256[] calldata tokenAmountsOut
    ) external view returns (uint256 lpAmountIn);

    //////////////////// RESERVES ////////////////////

    /**
     * @notice Syncs the Well's reserves with the Well's balances of underlying tokens. If the reserves
     * increase, mints at least `minLpAmountOut` LP Tokens to `recipient`.
     * @param recipient The address to receive the LP tokens
     * @param minLpAmountOut The minimum amount of LP tokens to receive
     * @return lpAmountOut The amount of LP tokens received
     * @dev Can be used in a multicall using a contract like Pipeline to perform gas efficient additions of liquidity.
     * No deadline is needed since this function does not use the user's assets. If adding liquidity in a multicall,
     * then a deadline check can be added to the multicall.
     * If `sync` decreases the Well's reserves, then no LP tokens are minted and `lpAmountOut` must be 0.
     */
    function sync(address recipient, uint256 minLpAmountOut) external returns (uint256 lpAmountOut);

    /**
     * @notice Calculates the amount of LP Tokens received from syncing the Well's reserves with the Well's balances.
     * @return lpAmountOut The amount of LP tokens received
     */
    function getSyncOut() external view returns (uint256 lpAmountOut);

    /**
     * @notice Sends excess tokens held by the Well to the `recipient`.
     * @param recipient The address to send the tokens
     * @return skimAmounts The amount of each token skimmed
     * @dev No deadline is needed since this function does not use the user's assets.
     */
    function skim(address recipient) external returns (uint256[] memory skimAmounts);

    /**
     * @notice Gets the reserves of each token held by the Well.
     */
    function getReserves() external view returns (uint256[] memory reserves);

    /**
     * @notice Returns whether or not the Well is initialized if it requires initialization.
     * If a Well does not require initialization, it should always return `true`.
     */
    function isInitialized() external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IWell} from "contracts/interfaces/basin/IWell.sol";
import {C} from "contracts/C.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {AppStorage, LibAppStorage} from "contracts/libraries/LibAppStorage.sol";

/**
 * @title LibBarnRaise
 * @author Brendan
 * @notice Library fetching Barn Raise Token
 */
library LibBarnRaise {
    function getBarnRaiseToken() internal view returns (address) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        IERC20[] memory tokens = IWell(getBarnRaiseWell()).tokens();
        return address(address(tokens[0]) == s.sys.tokens.bean ? tokens[1] : tokens[0]);
    }

    function getBarnRaiseWell() internal view returns (address) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.silo.unripeSettings[s.sys.tokens.urLp].underlyingToken;
    }
}

/*
 SPDX-License-Identifier: MIT
*/

pragma solidity ^0.8.20;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "../interfaces/IDiamondLoupe.sol";

library LibDiamond {
    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

    struct FacetAddressAndPosition {
        address facetAddress;
        uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
    }

    struct FacetFunctionSelectors {
        bytes4[] functionSelectors;
        uint256 facetAddressPosition; // position of facetAddress in facetAddresses array
    }

    struct DiamondStorage {
        // maps function selector to the facet address and
        // the position of the selector in the facetFunctionSelectors.selectors array
        mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
        // maps facet addresses to function selectors
        mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
        // facet addresses
        address[] facetAddresses;
        // Used to query if a contract implements an interface.
        // Used to implement ERC-165.
        mapping(bytes4 => bool) supportedInterfaces;
        // owner of the contract
        address contractOwner;
    }

    function diamondStorage() internal pure returns (DiamondStorage storage ds) {
        bytes32 position = DIAMOND_STORAGE_POSITION;
        assembly {
            ds.slot := position
        }
    }

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    function setContractOwner(address _newOwner) internal {
        DiamondStorage storage ds = diamondStorage();
        address previousOwner = ds.contractOwner;
        ds.contractOwner = _newOwner;
        emit OwnershipTransferred(previousOwner, _newOwner);
    }

    function contractOwner() internal view returns (address contractOwner_) {
        contractOwner_ = diamondStorage().contractOwner;
    }

    function enforceIsOwnerOrContract() internal view {
        require(
            msg.sender == diamondStorage().contractOwner || msg.sender == address(this),
            "LibDiamond: Must be contract or owner"
        );
    }

    function enforceIsContractOwner() internal view {
        require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
    }

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

    function addDiamondFunctions(address _diamondCutFacet, address _diamondLoupeFacet) internal {
        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](2);
        bytes4[] memory functionSelectors = new bytes4[](1);
        functionSelectors[0] = IDiamondCut.diamondCut.selector;
        cut[0] = IDiamondCut.FacetCut({
            facetAddress: _diamondCutFacet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: functionSelectors
        });
        functionSelectors = new bytes4[](5);
        functionSelectors[0] = IDiamondLoupe.facets.selector;
        functionSelectors[1] = IDiamondLoupe.facetFunctionSelectors.selector;
        functionSelectors[2] = IDiamondLoupe.facetAddresses.selector;
        functionSelectors[3] = IDiamondLoupe.facetAddress.selector;
        functionSelectors[4] = IERC165.supportsInterface.selector;
        cut[1] = IDiamondCut.FacetCut({
            facetAddress: _diamondLoupeFacet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: functionSelectors
        });
        diamondCut(cut, address(0), "");
    }

    // Internal function version of diamondCut
    function diamondCut(
        IDiamondCut.FacetCut[] memory _diamondCut,
        address _init,
        bytes memory _calldata
    ) internal {
        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
            if (action == IDiamondCut.FacetCutAction.Add) {
                addFunctions(
                    _diamondCut[facetIndex].facetAddress,
                    _diamondCut[facetIndex].functionSelectors
                );
            } else if (action == IDiamondCut.FacetCutAction.Replace) {
                replaceFunctions(
                    _diamondCut[facetIndex].facetAddress,
                    _diamondCut[facetIndex].functionSelectors
                );
            } else if (action == IDiamondCut.FacetCutAction.Remove) {
                removeFunctions(
                    _diamondCut[facetIndex].facetAddress,
                    _diamondCut[facetIndex].functionSelectors
                );
            } else {
                revert("LibDiamondCut: Incorrect FacetCutAction");
            }
        }
        emit DiamondCut(_diamondCut, _init, _calldata);
        initializeDiamondCut(_init, _calldata);
    }

    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint96 selectorPosition = uint96(
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
        );
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            addFacet(ds, _facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(
                oldFacetAddress == address(0),
                "LibDiamondCut: Can't add function that already exists"
            );
            addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
        uint96 selectorPosition = uint96(
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.length
        );
        // add new facet address if it does not exist
        if (selectorPosition == 0) {
            addFacet(ds, _facetAddress);
        }
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            require(
                oldFacetAddress != _facetAddress,
                "LibDiamondCut: Can't replace function with same function"
            );
            removeFunction(ds, oldFacetAddress, selector);
            addFunction(ds, selector, selectorPosition, _facetAddress);
            selectorPosition++;
        }
    }

    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
        require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
        DiamondStorage storage ds = diamondStorage();
        // if function does not exist then do nothing and return
        require(
            _facetAddress == address(0),
            "LibDiamondCut: Remove facet address must be address(0)"
        );
        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
            bytes4 selector = _functionSelectors[selectorIndex];
            address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
            removeFunction(ds, oldFacetAddress, selector);
        }
    }

    function addFacet(DiamondStorage storage ds, address _facetAddress) internal {
        enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
        ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length;
        ds.facetAddresses.push(_facetAddress);
    }

    function addFunction(
        DiamondStorage storage ds,
        bytes4 _selector,
        uint96 _selectorPosition,
        address _facetAddress
    ) internal {
        ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition;
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);
        ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
    }

    function removeFunction(
        DiamondStorage storage ds,
        address _facetAddress,
        bytes4 _selector
    ) internal {
        require(
            _facetAddress != address(0),
            "LibDiamondCut: Can't remove function that doesn't exist"
        );
        // an immutable function is a function defined directly in a diamond
        require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
        // replace selector with last selector, then delete last selector
        uint256 selectorPosition = ds
            .selectorToFacetAndPosition[_selector]
            .functionSelectorPosition;
        uint256 lastSelectorPosition = ds
            .facetFunctionSelectors[_facetAddress]
            .functionSelectors
            .length - 1;
        // if not the same then replace _selector with lastSelector
        if (selectorPosition != lastSelectorPosition) {
            bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                lastSelectorPosition
            ];
            ds.facetFunctionSelectors[_facetAddress].functionSelectors[
                selectorPosition
            ] = lastSelector;
            ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(
                selectorPosition
            );
        }
        // delete the last selector
        ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
        delete ds.selectorToFacetAndPosition[_selector];

        // if no more selectors for facet address then delete the facet address
        if (lastSelectorPosition == 0) {
            // replace facet address with last facet address and delete last facet address
            uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
            uint256 facetAddressPosition = ds
                .facetFunctionSelectors[_facetAddress]
                .facetAddressPosition;
            if (facetAddressPosition != lastFacetAddressPosition) {
                address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                ds
                    .facetFunctionSelectors[lastFacetAddress]
                    .facetAddressPosition = facetAddressPosition;
            }
            ds.facetAddresses.pop();
            delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
        }
    }

    function initializeDiamondCut(address _init, bytes memory _calldata) internal {
        if (_init == address(0)) {
            require(
                _calldata.length == 0,
                "LibDiamondCut: _init is address(0) but_calldata is not empty"
            );
        } else {
            require(
                _calldata.length > 0,
                "LibDiamondCut: _calldata is empty but _init is not address(0)"
            );
            if (_init != address(this)) {
                enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
            }
            (bool success, bytes memory error) = _init.delegatecall(_calldata);
            if (!success) {
                if (error.length > 0) {
                    // bubble up the error
                    revert(string(error));
                } else {
                    revert("LibDiamondCut: _init function reverted");
                }
            }
        }
    }

    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
        uint256 contractSize;
        assembly {
            contractSize := extcodesize(_contract)
        }
        require(contractSize > 0, _errorMessage);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @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);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // 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 cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

/*
 SPDX-License-Identifier: MIT
*/

pragma solidity ^0.8.20;

import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {ICumulativePump} from "contracts/interfaces/basin/pumps/ICumulativePump.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IWell, Call} from "contracts/interfaces/basin/IWell.sol";
import {C} from "contracts/C.sol";
import {LibAppStorage} from "../LibAppStorage.sol";
import {AppStorage} from "contracts/beanstalk/storage/AppStorage.sol";
import {LibUsdOracle} from "contracts/libraries/Oracle/LibUsdOracle.sol";
import {LibRedundantMath128} from "contracts/libraries/LibRedundantMath128.sol";
import {IMultiFlowPumpWellFunction} from "contracts/interfaces/basin/pumps/IMultiFlowPumpWellFunction.sol";
import {IBeanstalkWellFunction} from "contracts/interfaces/basin/IBeanstalkWellFunction.sol";

interface IERC20Decimals {
    function decimals() external view returns (uint8);
}

/**
 * @title Well Library
 * Contains helper functions for common Well related functionality.
 **/
library LibWell {
    using LibRedundantMath256 for uint256;
    using LibRedundantMath128 for uint128;

    // The BDV Selector that all Wells should be whitelisted with.
    bytes4 internal constant WELL_BDV_SELECTOR = 0xc84c7727;

    uint256 private constant BEAN_UNIT = 1e6;

    function getRatiosAndBeanIndex(
        IERC20[] memory tokens
    ) internal view returns (uint[] memory ratios, uint beanIndex, bool success) {
        return getRatiosAndBeanIndex(tokens, 0);
    }

    /**
     * @dev Returns the price ratios between `tokens` and the index of Bean in `tokens`.
     * These actions are combined into a single function for gas efficiency.
     */
    function getRatiosAndBeanIndex(
        IERC20[] memory tokens,
        uint256 lookback
    ) internal view returns (uint[] memory ratios, uint beanIndex, bool success) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        success = true;
        ratios = new uint[](tokens.length);
        beanIndex = type(uint256).max;
        bool isMillion;
        address bean = s.sys.tokens.bean;

        // fetch the bean index and check whether the ratios precision needs to be increased.
        for (uint i; i < tokens.length; ++i) {
            if (address(tokens[i]) == bean) {
                beanIndex = i;
            } else if (IERC20Decimals(address(tokens[i])).decimals() <= 8) {
                // if the nonBean token in the well has a low decimal precision,
                // set `isMillion` such that the ratio is set to be on a million basis.
                isMillion = true;
            }
        }

        // get the target ratios.
        for (uint i; i < tokens.length; ++i) {
            if (address(tokens[i]) == bean) {
                if (isMillion) {
                    ratios[i] = 1e12;
                } else {
                    ratios[i] = 1e6;
                }
            } else {
                if (isMillion) {
                    ratios[i] = LibUsdOracle.getMillionUsdPrice(address(tokens[i]), lookback);
                } else {
                    ratios[i] = LibUsdOracle.getUsdPrice(address(tokens[i]), lookback);
                }
                if (ratios[i] == 0) {
                    success = false;
                }
            }
        }

        require(beanIndex != type(uint256).max, "Bean not in Well.");
    }

    /**
     * @dev Returns the index of Bean in a list of tokens.
     */
    function getBeanIndex(IERC20[] memory tokens) internal view returns (uint beanIndex) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        for (beanIndex; beanIndex < tokens.length; ++beanIndex) {
            if (s.sys.tokens.bean == address(tokens[beanIndex])) {
                return beanIndex;
            }
        }
        revert("Bean not in Well.");
    }

    /**
     * @dev Returns the first ERC20 well token that is not Bean.
     */
    function getNonBeanIndex(IERC20[] memory tokens) internal view returns (uint nonBeanIndex) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        for (nonBeanIndex; nonBeanIndex < tokens.length; ++nonBeanIndex) {
            if (s.sys.tokens.bean != address(tokens[nonBeanIndex])) {
                return nonBeanIndex;
            }
        }
        revert("Non-Bean not in Well.");
    }

    /**
     * @dev Returns the index of Bean given a Well.
     */
    function getBeanIndexFromWell(address well) internal view returns (uint beanIndex) {
        IERC20[] memory tokens = IWell(well).tokens();
        beanIndex = getBeanIndex(tokens);
    }

    function getNonBeanTokenFromWell(address well) internal view returns (IERC20 nonBeanToken) {
        IERC20[] memory tokens = IWell(well).tokens();
        return tokens[getNonBeanIndex(tokens)];
    }

    /**
     * @dev Returns the non-Bean token within a Well.
     * Assumes a well with 2 tokens only, with Bean being one of them.
     * Cannot fail (and thus revert), as wells cannot have 2 of the same tokens as the pairing.
     */
    function getNonBeanTokenAndIndexFromWell(
        address well
    ) internal view returns (address, uint256) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        IERC20[] memory tokens = IWell(well).tokens();
        for (uint256 i; i < tokens.length; i++) {
            if (address(tokens[i]) != s.sys.tokens.bean) {
                return (address(tokens[i]), i);
            }
        }
        revert("LibWell: invalid well:");
    }

    /**
     * @dev Returns whether an address is a whitelisted Well by checking
     * if the BDV function selector is the `wellBdv` function.
     */
    function isWell(address well) internal view returns (bool _isWell) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return s.sys.silo.assetSettings[well].selector == WELL_BDV_SELECTOR;
    }

    /**
     * @notice gets the non-bean usd liquidity of a well,
     * using the twa reserves and price in storage.
     *
     * @dev this is done for gas efficency purposes, rather than calling the pump multiple times.
     * This function should be called after the reserves for the well have been set.
     * Currently this is only done in {seasonFacet.sunrise}.
     *
     * if LibWell.getUsdTokenPriceForWell() returns 1, then this function is called without the reserves being set.
     * if s.sys.usdTokenPrice[well] or s.sys.twaReserves[well] returns 0, then the oracle failed to compute
     * a valid price this Season, and thus beanstalk cannot calculate the usd liquidity.
     */
    function getWellTwaUsdLiquidityFromReserves(
        address well,
        uint256[] memory twaReserves
    ) internal view returns (uint256 usdLiquidity) {
        uint256 tokenUsd = getUsdTokenPriceForWell(well);
        (address token, uint256 j) = getNonBeanTokenAndIndexFromWell(well);
        if (tokenUsd > 1) {
            return twaReserves[j].mul(1e18).div(tokenUsd);
        }

        // if tokenUsd == 0, then the beanstalk could not compute a valid eth price,
        // and should return 0. if s.sys.twaReserves[well].reserve1 is 0, the previous if block will return 0.
        if (tokenUsd == 0) {
            return 0;
        }

        // if the function reaches here, then this is called outside the sunrise function
        // (i.e, seasonGetterFacet.getLiquidityToSupplyRatio()).We use LibUsdOracle
        // to get the price. This should never be reached during sunrise and thus
        // should not impact gas.
        // LibUsdOracle returns the price with 1e6 precision.
        // twaReserves has the same decimal precision as the token.
        // The return value is then used in LibEvaluate.calcLPToSupplyRatio that assumes 18 decimal precision,
        // so we need to account for whitelisted tokens that have less than 18 decimals by dividing the
        // precision by the token decimals.
        // Here tokenUsd = 1 so 1e6 * 1eN * 1e12 / 1eN = 1e18.

        uint8 tokenDecimals = IERC20Decimals(token).decimals();
        return
            LibUsdOracle.getTokenPrice(token).mul(twaReserves[j]).mul(1e12).div(
                10 ** tokenDecimals
            );
    }

    /**
     * @dev Sets the price in {AppStorage.usdTokenPrice} given a set of ratios.
     * Assumes
     * 1) Ratios correspond to the Constant Product Well indexes.
     * 2) the Well is a 2 token Well.
     */
    function setUsdTokenPriceForWell(address well, uint256[] memory ratios) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();

        // If the reserves length is 0, then {LibWellMinting} failed to compute
        // valid manipulation resistant reserves and thus the price is set to 0
        // indicating that the oracle failed to compute a valid price this Season.
        if (ratios.length == 0) {
            s.sys.usdTokenPrice[well] = 0;
        } else {
            (, uint256 j) = getNonBeanTokenAndIndexFromWell(well);
            uint256 i = j == 0 ? 1 : 0;
            // usdTokenPrice is scaled down to USD/TOKEN, in the cases where
            // Beanstalk calculated the MILLION_USD/TOKEN price instead of USD/TOKEN price.
            // Beanstalk accepts the loss of precision here, as `usdTokenPrice[well]` is used for
            // calculating the liquidity and excessive price.
            s.sys.usdTokenPrice[well] = (ratios[j] * 1e6) / ratios[i];
        }
    }

    /**
     * @notice Returns the USD / TKN price stored in {AppStorage.usdTokenPrice}.
     * @dev assumes TKN has 18 decimals.
     */
    function getUsdTokenPriceForWell(address well) internal view returns (uint tokenUsd) {
        tokenUsd = LibAppStorage.diamondStorage().sys.usdTokenPrice[well];
    }

    /**
     * @notice resets token price for a well to 1.
     * @dev must be called at the end of sunrise() once the
     * price is not needed anymore to save gas.
     */
    function resetUsdTokenPriceForWell(address well) internal {
        LibAppStorage.diamondStorage().sys.usdTokenPrice[well] = 1;
    }

    /**
     * @dev Sets the twaReserves in {AppStorage.usdTokenPrice}.
     * assumes the twaReserve indexes correspond to the Constant Product Well indexes.
     * if the length of the twaReserves is 0, then the minting oracle is off.
     *
     */
    function setTwaReservesForWell(address well, uint256[] memory twaReserves) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        // if the length of twaReserves is 0, then return 0.
        // the length of twaReserves should never be 1, but
        // is added to prevent revert.
        if (twaReserves.length <= 1) {
            delete s.sys.twaReserves[well].reserve0;
            delete s.sys.twaReserves[well].reserve1;
        } else {
            // safeCast not needed as the reserves are uint128 in the wells.
            s.sys.twaReserves[well].reserve0 = uint128(twaReserves[0]);
            s.sys.twaReserves[well].reserve1 = uint128(twaReserves[1]);
        }
    }

    /**
     * @notice Returns the TKN / USD price stored in {AppStorage.usdTokenPrice}.
     * @dev assumes TKN has 18 decimals.
     */
    function getTwaReservesForWell(
        address well
    ) internal view returns (uint256[] memory twaReserves) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        twaReserves = new uint256[](2);
        twaReserves[0] = s.sys.twaReserves[well].reserve0;
        twaReserves[1] = s.sys.twaReserves[well].reserve1;
    }

    /**
     * @notice resets token price for a well to 1.
     * @dev must be called at the end of sunrise() once the
     * price is not needed anymore to save gas.
     */
    function resetTwaReservesForWell(address well) internal {
        AppStorage storage s = LibAppStorage.diamondStorage();
        s.sys.twaReserves[well].reserve0 = 1;
        s.sys.twaReserves[well].reserve1 = 1;
    }

    /**
     * @notice returns the price in terms of TKN/BEAN.
     * (if eth is 1000 beans, this function will return 1000e6);
     */
    function getTokenBeanPriceFromTwaReserves(address well) internal view returns (uint256 price) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        // s.sys.twaReserve[well] should be set prior to this function being called.
        // 'price' is in terms of reserve0:reserve1.
        if (s.sys.twaReserves[well].reserve0 == 0 || s.sys.twaReserves[well].reserve1 == 0) {
            price = 0;
        } else {
            // fetch the bean index from the well in order to properly return the bean price.
            uint256[] memory reserves = new uint256[](2);
            reserves[0] = s.sys.twaReserves[well].reserve0;
            reserves[1] = s.sys.twaReserves[well].reserve1;

            Call memory wellFunction = IWell(well).wellFunction();

            if (getBeanIndexFromWell(well) == 0) {
                price = calculateTokenBeanPriceFromReserves(well, 0, 1, reserves, wellFunction);
            } else {
                price = calculateTokenBeanPriceFromReserves(well, 1, 0, reserves, wellFunction);
            }
        }
    }

    /**
     * @notice Calculates the token price in terms of Bean by increasing
     * the bean reserves of the given well by 1 and recaclulating the new reserves,
     * while maintaining the same liquidity levels.
     * This essentially simulates a swap of 1 Bean for the non bean token and quotes the price.
     */
    function calculateTokenBeanPriceFromReserves(
        address well,
        uint256 beanIndex,
        uint256 nonBeanIndex,
        uint256[] memory reserves,
        Call memory wellFunction
    ) internal view returns (uint256 price) {
        address nonBeanToken = address(IWell(well).tokens()[nonBeanIndex]);
        uint256 lpTokenSupply = IBeanstalkWellFunction(wellFunction.target).calcLpTokenSupply(
            reserves,
            wellFunction.data
        );

        uint256 oldReserve = reserves[nonBeanIndex];
        reserves[beanIndex] = reserves[beanIndex] + BEAN_UNIT;
        uint256 newReserve = IBeanstalkWellFunction(wellFunction.target).calcReserve(
            reserves,
            nonBeanIndex,
            lpTokenSupply,
            wellFunction.data
        );
        // Measure the delta of the non bean reserve.
        // Due to the invariant of the well function, old reserve > new reserve.
        uint256 delta = oldReserve - newReserve;
        price = (10 ** (IERC20Decimals(nonBeanToken).decimals() + 6)) / delta;
    }

    function getTwaReservesFromStorageOrBeanstalkPump(
        address well
    ) internal view returns (uint256[] memory twaReserves) {
        twaReserves = getTwaReservesForWell(well);
        if (twaReserves[0] == 1) {
            twaReserves = getTwaReservesFromPump(well);
        }
    }

    /**
     * @notice gets the TwaReserves of a given well.
     * @dev only supports wells that are whitelisted in beanstalk.
     * the initial timestamp and reserves is the timestamp of the start
     * of the last season. wrapped in try/catch to return gracefully.
     */
    function getTwaReservesFromPump(address well) internal view returns (uint256[] memory) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        Call[] memory pumps = IWell(well).pumps();
        try
            ICumulativePump(pumps[0].target).readTwaReserves(
                well,
                s.sys.wellOracleSnapshots[well],
                uint40(s.sys.season.timestamp),
                pumps[0].data
            )
        returns (uint[] memory twaReserves, bytes memory) {
            return twaReserves;
        } catch {
            return (new uint256[](2));
        }
    }

    /**
     * @notice returns the twa reserves for well,
     * given the cumulative reserves and timestamp.
     * @dev wrapped in a try/catch to return gracefully.
     */
    function getTwaReservesFromPump(
        address well,
        bytes memory cumulativeReserves,
        uint40 timestamp
    ) internal view returns (uint256[] memory) {
        Call[] memory pump = IWell(well).pumps();
        try
            ICumulativePump(pump[0].target).readTwaReserves(
                well,
                cumulativeReserves,
                timestamp,
                pump[0].data
            )
        returns (uint[] memory twaReserves, bytes memory) {
            return twaReserves;
        } catch {
            return (new uint256[](2));
        }
    }

    /**
     * @notice gets the TwaLiquidity of a given well.
     * @dev only supports wells that are whitelisted in beanstalk.
     * the initial timestamp and reserves is the timestamp of the start
     * of the last season.
     */
    function getTwaLiquidityFromPump(
        address well,
        uint256 tokenUsdPrice
    ) internal view returns (uint256 usdLiquidity) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        (, uint256 j) = getNonBeanTokenAndIndexFromWell(well);
        Call[] memory pumps = IWell(well).pumps();
        try
            ICumulativePump(pumps[0].target).readTwaReserves(
                well,
                s.sys.wellOracleSnapshots[well],
                uint40(s.sys.season.timestamp),
                pumps[0].data
            )
        returns (uint[] memory twaReserves, bytes memory) {
            usdLiquidity = tokenUsdPrice.mul(twaReserves[j]).div(1e6);
        } catch {
            // if pump fails to return a value, return 0.
            usdLiquidity = 0;
        }
    }
}

/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity ^0.8.20;

import {C} from "contracts/C.sol";
import {LibUniswapOracle} from "./LibUniswapOracle.sol";
import {LibChainlinkOracle} from "./LibChainlinkOracle.sol";
import {IUniswapV3PoolImmutables} from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import {LibAppStorage, AppStorage} from "contracts/libraries/LibAppStorage.sol";
import {Implementation} from "contracts/beanstalk/storage/System.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

interface IERC20Decimals {
    function decimals() external view returns (uint8);
}

/**
 * @title Usd Oracle Library
 * @notice Contains functionalty to fetch the manipulation resistant USD price of different tokens.
 * @dev currently supports:
 **/
library LibUsdOracle {
    using LibRedundantMath256 for uint256;

    uint256 constant UNISWAP_DENOMINATOR = 1e6;

    function getUsdPrice(address token) internal view returns (uint256) {
        return getUsdPrice(token, 0);
    }

    /**
     * @dev Returns the price of 1 USD in terms of `token` with the option of using a lookback. (Usd:token Price)
     * `lookback` should be 0 if the instantaneous price is desired. Otherwise, it should be the
     * TWAP lookback in seconds.
     * If using a non-zero lookback, it is recommended to use a substantially large `lookback`
     * (> 900 seconds) to protect against manipulation.
     */
    function getUsdPrice(address token, uint256 lookback) internal view returns (uint256) {
        // call external implementation for token
        // note passing decimals controls pricing order (token:usd vs usd:token)
        return getTokenPriceFromExternal(token, IERC20Decimals(token).decimals(), lookback);
    }

    function getTokenPrice(address token) internal view returns (uint256) {
        return getTokenPrice(token, 0);
    }

    /**
     * @notice returns the price of a given token in USD (token:Usd Price)
     * @dev if ETH returns 1000 USD, this function returns 1000
     * (ignoring decimal precision)
     */
    function getTokenPrice(address token, uint256 lookback) internal view returns (uint256) {
        // call external implementation for token
        return getTokenPriceFromExternal(token, 0, lookback);
    }

    /**
     * @notice gets the token price from an external oracle.
     * @dev if address is 0, use the current contract.
     * If encodeType is 0x01, use the default chainlink implementation.
     * Returns 0 rather than reverting if the call fails.
     * Note: token here refers to the non bean token when quoting for a well price.
     */
    function getTokenPriceFromExternal(
        address token,
        uint256 tokenDecimals,
        uint256 lookback
    ) internal view returns (uint256 tokenPrice) {
        return getTokenPriceFromExternal(token, tokenDecimals, lookback, false);
    }

    /**
     * @notice returns the price of 1 Million USD in terms of `token` with the option of using a lookback.
     * @dev `LibWell.getRatiosAndBeanIndex` attempts to calculate the target ratios by fetching the usdPrice of each token.
     * For tokens with low decimal precision and high prices (ex. WBTC), using the usd:token price would result in a
     * large amount of precision loss. For this reason, tokens with less than 8 decimals use the 1 Million USD price instead..
     */
    function getMillionUsdPrice(address token, uint256 lookback) internal view returns (uint256) {
        return getTokenPriceFromExternal(token, IERC20Decimals(token).decimals(), lookback, true);
    }

    /**
     * @notice internal helper function for `getTokenPriceFromExternal`.
     * @dev the `isMillion` flag is used in `LibChainlinkOracle.getTokenPrice` to
     * return the MILLION_TOKEN2/TOKEN1 price, in cases where the price of TOKEN1 is extremely high (relative to token 2),
     * and when the decimals is very low.
     */
    function getTokenPriceFromExternal(
        address token,
        uint256 tokenDecimals,
        uint256 lookback,
        bool isMillion
    ) private view returns (uint256 tokenPrice) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        Implementation memory oracleImpl = s.sys.oracleImplementation[token];

        // If the encode type is type 1, use the default chainlink implementation instead.
        // `target` refers to the address of the price aggergator implmentation
        if (oracleImpl.encodeType == bytes1(0x01)) {
            return
                LibChainlinkOracle.getTokenPrice(
                    oracleImpl.target, // chainlink Aggergator Address
                    abi.decode(oracleImpl.data, (uint256)), // timeout
                    tokenDecimals, // token decimals
                    lookback,
                    isMillion
                );
        } else if (oracleImpl.encodeType == bytes1(0x02)) {
            // if the encodeType is type 2, use a uniswap oracle implementation.

            // the uniswap oracle implementation combines the use of the chainlink and uniswap oracles.
            // the chainlink oracle is used to get the price of the non-oracle token (for example USDC) in order to
            // use that as a dollar representation
            address chainlinkToken = IUniswapV3PoolImmutables(oracleImpl.target).token0();

            if (chainlinkToken == token) {
                chainlinkToken = IUniswapV3PoolImmutables(oracleImpl.target).token1();
            }

            // get twap from the `chainlinkToken` to `token`
            // exchange 1 `token` for `chainlinkToken`.
            tokenPrice = LibUniswapOracle.getTwap(
                lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
                oracleImpl.target,
                token,
                chainlinkToken,
                tokenDecimals == 0
                    ? uint128(10 ** IERC20Decimals(token).decimals())
                    : uint128(10 ** tokenDecimals)
            );

            // call chainlink oracle from the OracleImplmentation contract
            Implementation memory chainlinkOracle = s.sys.oracleImplementation[chainlinkToken];

            // return the CL_TOKEN/USD or USD/CL_TOKEN, depending on `tokenDecimals`.
            uint256 chainlinkTokenDecimals = IERC20Decimals(chainlinkToken).decimals();
            uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
                chainlinkOracle.target,
                abi.decode(chainlinkOracle.data, (uint256)), // timeout
                tokenDecimals == 0 ? tokenDecimals : chainlinkTokenDecimals,
                lookback,
                false
            );

            // if token decimals != 0, Beanstalk is attempting to query the USD/TOKEN price, and
            // thus the price needs to be inverted.
            if (tokenDecimals != 0) {
                // invert tokenPrice (to get CL_TOKEN/TOKEN).
                // `tokenPrice` has 6 decimal precision (see {LibUniswapOracle.getTwap}).
                // `tokenPrice` is scaled up to 1 million units, if the `isMillion` flag is enabled.
                if (isMillion) {
                    tokenPrice = (1e12 * (10 ** tokenDecimals)) / tokenPrice;
                } else {
                    tokenPrice = (1e6 * (10 ** tokenDecimals)) / tokenPrice;
                }
                // return the USD/TOKEN price.
                // 1e6 * 1e`n` / 1e`n` = 1e6
                return (tokenPrice * chainlinkTokenPrice) / (10 ** chainlinkTokenDecimals);
            }

            return (tokenPrice * chainlinkTokenPrice) / UNISWAP_DENOMINATOR;
        }

        // Non-zero addresses are enforced in verifyOracleImplementation, this is just an extra check.
        if (oracleImpl.target == address(0)) return 0;

        // if `isMillion` is enabled, append the boolean into the oracleImpl,
        // such that the oracle implementation can use the data.
        bytes memory oracleImplData = oracleImpl.data;
        if (isMillion) {
            oracleImplData = abi.encodePacked(oracleImpl.data, isMillion);
        }

        (bool success, bytes memory data) = oracleImpl.target.staticcall(
            abi.encodeWithSelector(oracleImpl.selector, tokenDecimals, lookback, oracleImplData)
        );

        if (!success) return 0;
        assembly {
            tokenPrice := mload(add(data, add(0x20, 0)))
        }
    }
}

/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity ^0.8.20;

/**
 * @title Lib Tractor
 * @author funderbrker
 **/
library LibTractor {
    enum CounterUpdateType {
        INCREASE,
        DECREASE
    }

    bytes32 private constant TRACTOR_HASHED_NAME = keccak256(bytes("Tractor"));
    bytes32 private constant EIP712_TYPE_HASH =
        keccak256(
            bytes(
                "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
            )
        );
    bytes32 public constant BLUEPRINT_TYPE_HASH =
        keccak256(
            bytes(
                "Blueprint(address publisher,bytes data,bytes32[] operatorPasteInstrs,uint256 maxNonce,uint256 startTime,uint256 endTime)"
            )
        );

    event TractorVersionSet(string version);

    struct TractorStorage {
        // Number of times the blueprint has been run.
        mapping(bytes32 => uint256) blueprintNonce;
        // Publisher Address => counter id => counter value.
        mapping(address => mapping(bytes32 => uint256)) blueprintCounters;
        // Publisher of current operations. Set to address(1) when no active publisher.
        address payable activePublisher;
        // Version of Tractor. Only Blueprints using current Version can run.
        string version;
    }

    // Blueprint stores blueprint related values
    struct Blueprint {
        address publisher;
        bytes data;
        bytes32[] operatorPasteInstrs;
        uint256 maxNonce;
        uint256 startTime;
        uint256 endTime;
    }

    /**
     * @notice Stores blueprint, hash, and signature, which enables verification.
     */
    struct Requisition {
        Blueprint blueprint;
        bytes32 blueprintHash; // including this is not strictly necessary, but helps avoid hashing more than once on chain
        bytes signature;
    }

    /**
     * @notice Get tractor storage from storage.
     * @return ts Storage object containing tractor data
     */
    function _tractorStorage() internal pure returns (TractorStorage storage ts) {
        // keccak256("diamond.storage.tractor") == 0x7efbaaac9214ca1879e26b4df38e29a72561affb741bba775ce66d5bb6a82a07
        assembly {
            ts.slot := 0x7efbaaac9214ca1879e26b4df38e29a72561affb741bba775ce66d5bb6a82a07
        }
    }

    /**
     * @notice Set the tractor hashed version.
     */
    function _setVersion(string memory version) internal {
        _tractorStorage().version = version;
        emit TractorVersionSet(version);
    }

    /**
     * @notice Increment the blueprint nonce by 1.
     * @param blueprintHash blueprint hash
     */
    function _incrementBlueprintNonce(bytes32 blueprintHash) internal {
        _tractorStorage().blueprintNonce[blueprintHash]++;
    }

    /**
     * @notice Cancel blueprint.
     * @dev set blueprintNonce to type(uint256).max
     * @param blueprintHash blueprint hash
     */
    function _cancelBlueprint(bytes32 blueprintHash) internal {
        _tractorStorage().blueprintNonce[blueprintHash] = type(uint256).max;
    }

    /**
     * @notice Set blueprint publisher address.
     * @param publisher blueprint publisher address
     */
    function _setPublisher(address payable publisher) internal {
        TractorStorage storage ts = _tractorStorage();
        require(
            uint160(bytes20(address(ts.activePublisher))) <= 1,
            "LibTractor: publisher already set"
        );
        ts.activePublisher = publisher;
    }

    /**
     * @notice Reset blueprint publisher address.
     */
    function _resetPublisher() internal {
        _tractorStorage().activePublisher = payable(address(1));
    }

    /** @notice Return current activePublisher address.
     * @return publisher current activePublisher address
     */
    function _getActivePublisher() internal view returns (address payable) {
        return _tractorStorage().activePublisher;
    }

    /** @notice Return current activePublisher address or msg.sender if no active blueprint.
     * @return user to take actions on behalf of
     */
    function _user() internal view returns (address payable user) {
        user = _getActivePublisher();
        if (uint160(bytes20(address(user))) <= 1) {
            user = payable(msg.sender);
        }
    }

    /**
     * @notice Get blueprint nonce.
     * @param blueprintHash blueprint hash
     * @return nonce current blueprint nonce
     */
    function _getBlueprintNonce(bytes32 blueprintHash) internal view returns (uint256) {
        return _tractorStorage().blueprintNonce[blueprintHash];
    }

    /**
     * @notice Calculates blueprint hash.
     * @dev https://eips.ethereum.org/EIPS/eip-712
     * @dev  https://github.com/BeanstalkFarms/Beanstalk/pull/727#discussion_r1577293450
     * @param blueprint blueprint object
     * @return hash calculated Blueprint hash
     */
    function _getBlueprintHash(Blueprint calldata blueprint) internal view returns (bytes32) {
        return
            _hashTypedDataV4(
                keccak256(
                    abi.encode(
                        BLUEPRINT_TYPE_HASH,
                        blueprint.publisher,
                        keccak256(blueprint.data),
                        keccak256(abi.encodePacked(blueprint.operatorPasteInstrs)),
                        blueprint.maxNonce,
                        blueprint.startTime,
                        blueprint.endTime
                    )
                )
            );
    }

    /**
     * @notice Hashes in an EIP712 compliant way.
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * Sourced from OpenZeppelin 0.8 ECDSA lib.
     */
    function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
    }

    /**
     * @notice Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    EIP712_TYPE_HASH,
                    TRACTOR_HASHED_NAME,
                    keccak256(bytes(_tractorStorage().version)),
                    block.chainid,
                    address(this)
                )
            );
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

/**
 * @dev {ERC20} token, including:
 *
 *  - ability for holders to burn (destroy) their tokens
 *  - a minter role that allows for token minting (creation)
 *  - a pauser role that allows to stop all token transfers
 *
 * This contract uses {AccessControl} to lock permissioned functions using the
 * different roles - head to its documentation for details.
 *
 * The account that deploys the contract will be granted the minter and pauser
 * roles, as well as the default admin role, which will let it grant both minter
 * and pauser roles to other accounts.
 */
contract BeanstalkERC20 is
    ERC20Permit,
    ERC20Burnable,
    AccessControl // removed Context,
{
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE` and `MINTER_ROLE` to the
     * account that deploys the contract.
     * See {ERC20-constructor}.
     */
    constructor(
        address admin,
        string memory name,
        string memory symbol
    ) ERC20(name, symbol) ERC20Permit(name) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(MINTER_ROLE, admin);
    }

    /**
     * @dev Creates `amount` new tokens for `to`.
     *
     * See {ERC20-_mint}.
     *
     * Requirements:
     *
     * - the caller must have the `MINTER_ROLE`.
     */
    function mint(address to, uint256 amount) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "!Minter");
        _mint(to, amount);
    }

    /**
     * @dev Returns the number of decimals=
     * Beanstalk
     */
    function decimals() public view virtual override returns (uint8) {
        return 6;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

File 38 of 82 : AppStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {Account} from "./Account.sol";
import {System} from "./System.sol";

/**
 * @title AppStorage
 * @dev The Beanstalk diamond uses an AppStorage system that shares state across all facets.
 * @dev https://dev.to/mudgen/appstorage-pattern-for-state-variables-in-solidity-3lki
 */

/**
 * @title AppStorage
 * @notice Contains all state for the Beanstalk Diamond.
 * @param sys Contains shared state of the system as a whole.
 * @param accts Contains state of individual users.
 */
struct AppStorage {
    mapping(address => Account) accts;
    System sys;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;
interface IProxyAdmin {
    function upgrade(address proxy, address implementation) external;
}

/*
 SPDX-License-Identifier: MIT
*/

pragma solidity ^0.8.20;

import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";

/**
 * @title Decimal
 * @author dYdX
 *
 * Library that defines a fixed-point number with 18 decimal places.
 */
library Decimal {
    using LibRedundantMath256 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) {
        if (b.mul(BASE) > self.value) {
            revert(reason);
        }
        return D256({value: self.value.sub(b.mul(BASE))});
    }

    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) {
        if (greaterThan(b, self)) {
            revert(reason);
        }
        return D256({value: self.value.sub(b.value)});
    }

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

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title IPipeline
 * @author Publius
 * @notice Pipeline Interface – Pipeline creates a sandbox to execute any series of function calls on any series of protocols through \term{Pipe} functions.
 * Any assets left in Pipeline between transactions can be transferred out by any account.
 * Users Pipe a series of PipeCalls that each execute a function call to another protocol through Pipeline.
 **/

// PipeCalls specify a function call to be executed by Pipeline.
// Pipeline supports 2 types of PipeCalls: PipeCall and AdvancedPipeCall.

// PipeCall makes a function call with a static target address and callData.
struct PipeCall {
    address target;
    bytes data;
}

// AdvancedPipeCall makes a function call with a static target address and both static and dynamic callData.
// AdvancedPipeCalls support sending Ether in calls.
// [ PipeCall Type | Send Ether Flag | PipeCall Type data | Ether Value (only if flag == 1)]
// [ 1 byte        | 1 byte          | n bytes        | 0 or 32 bytes                      ]
// See LibClipboard.useClipboard for more details.
struct AdvancedPipeCall {
    address target;
    bytes callData;
    bytes clipboard;
}

interface IPipeline {
    function pipe(PipeCall calldata p) external payable returns (bytes memory result);

    function multiPipe(PipeCall[] calldata pipes) external payable returns (bytes[] memory results);

    function advancedPipe(
        AdvancedPipeCall[] calldata pipes
    ) external payable returns (bytes[] memory results);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @title IWellFunction
 * @notice Defines a relationship between token reserves and LP token supply.
 * @dev Well Functions can contain arbitrary logic, but should be deterministic
 * if expected to be used alongside a Pump. When interacing with a Well or
 * Well Function, always verify that the Well Function is valid.
 */
interface IWellFunction {
    /**
     * @notice Calculates the `j`th reserve given a list of `reserves` and `lpTokenSupply`.
     * @param reserves A list of token reserves. The jth reserve will be ignored, but a placeholder must be provided.
     * @param j The index of the reserve to solve for
     * @param lpTokenSupply The supply of LP tokens
     * @param data Extra Well function data provided on every call
     * @return reserve The resulting reserve at the jth index
     * @dev Should round up to ensure that Well reserves are marginally higher to enforce calcLpTokenSupply(...) >= totalSupply()
     */
    function calcReserve(
        uint[] memory reserves,
        uint j,
        uint lpTokenSupply,
        bytes calldata data
    ) external view returns (uint reserve);

    /**
     * @notice Gets the LP token supply given a list of reserves.
     * @param reserves A list of token reserves
     * @param data Extra Well function data provided on every call
     * @return lpTokenSupply The resulting supply of LP tokens
     * @dev Should round down to ensure so that the Well Token supply is marignally lower to enforce calcLpTokenSupply(...) >= totalSupply()
     */
    function calcLpTokenSupply(
        uint[] memory reserves,
        bytes calldata data
    ) external view returns (uint lpTokenSupply);

    /**
     * @notice Calculates the amount of each reserve token underlying a given amount of LP tokens.
     * @param lpTokenAmount An amount of LP tokens
     * @param reserves A list of token reserves
     * @param lpTokenSupply The current supply of LP tokens
     * @param data Extra Well function data provided on every call
     * @return underlyingAmounts The amount of each reserve token that underlies the LP tokens
     * @dev The constraint totalSupply() <= calcLPTokenSupply(...) must be held in the case where
     * `lpTokenAmount` LP tokens are burned in exchanged for `underlyingAmounts`. If the constraint
     * does not hold, then the Well Function is invalid.
     */
    function calcLPTokenUnderlying(
        uint lpTokenAmount,
        uint[] memory reserves,
        uint lpTokenSupply,
        bytes calldata data
    ) external view returns (uint[] memory underlyingAmounts);

    /**
     * @notice Returns the name of the Well function.
     */
    function name() external view returns (string memory);

    /**
     * @notice Returns the symbol of the Well function.
     */
    function symbol() external view returns (string memory);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {AppStorage, LibAppStorage} from "./LibAppStorage.sol";

/**
 * @title LibLockedUnderlying
 * @author Brendan
 * @notice Library to calculate the number of Underlying Tokens that would be locked if all of
 * the Unripe Tokens are Chopped.
 */
library LibLockedUnderlying {
    using LibRedundantMath256 for uint256;

    uint256 constant DECIMALS = 1e6;

    /**
     * @notice Return the amount of Underlying Tokens that would be locked if all of the Unripe Tokens
     * were chopped.
     */
    function getLockedUnderlying(
        address unripeToken,
        uint256 recapPercentPaid
    ) external view returns (uint256 lockedUnderlying) {
        AppStorage storage s = LibAppStorage.diamondStorage();
        return
            s
                .sys
                .silo
                .unripeSettings[unripeToken]
                .balanceOfUnderlying
                .mul(getPercentLockedUnderlying(unripeToken, recapPercentPaid))
                .div(1e18);
    }

    /**
     * @notice Return the % of Underlying Tokens that would be locked if all of the Unripe Tokens
     * were chopped.
     * @param unripeToken The address of the Unripe Token
     * @param recapPercentPaid The % of the Unripe Token that has been recapitalized
     *
     * @dev Solves the below equation for N_{⌈U/i⌉}:
     * N_{t+1} = N_t - π * i / (U - i * t)
     * where:
     *  - N_t is the number of Underlying Tokens at step t
     *  - U is the starting number of Unripe Tokens
     *  - π is the amount recapitalized
     *  - i is the number of Unripe Beans that are chopped at each step. i ~= 46,659 is used as this is aboutr
     *    the average Unripe Beans held per Farmer with a non-zero balance.
     *
     * The equation is solved by using a lookup table of N_{⌈U/i⌉} values for different values of
     * U and R (The solution is independent of N) as solving iteratively is too computationally
     * expensive and there is no more efficient way to solve the equation.
     *
     * The lookup threshold assumes no decimal precision. This library only supports
     * unripe tokens with 6 decimals.
     */
    function getPercentLockedUnderlying(
        address unripeToken,
        uint256 recapPercentPaid
    ) private view returns (uint256 percentLockedUnderlying) {
        uint256 unripeSupply = IERC20(unripeToken).totalSupply().div(DECIMALS);
        if (unripeSupply < 1_000_000) return 0; // If < 1_000_000 Assume all supply is unlocked.
        if (unripeSupply > 90_000_000) {
            if (recapPercentPaid > 0.1e6) {
                if (recapPercentPaid > 0.21e6) {
                    if (recapPercentPaid > 0.38e6) {
                        if (recapPercentPaid > 0.45e6) {
                            return 0.2691477202198985e18; // 90,000,000, 0.9
                        } else {
                            return 0.4245158057296602e18; // 90,000,000, 0.45
                        }
                    } else if (recapPercentPaid > 0.29e6) {
                        if (recapPercentPaid > 0.33e6) {
                            return 0.46634353868138156e18; // 90,000,000, 0.38
                        } else {
                            return 0.5016338055689489e18; // 90,000,000, 0.33
                        }
                    } else if (recapPercentPaid > 0.25e6) {
                        if (recapPercentPaid > 0.27e6) {
                            return 0.5339474169852891e18; // 90,000,000, 0.29
                        } else {
                            return 0.5517125463928281e18; // 90,000,000, 0.27
                        }
                    } else {
                        if (recapPercentPaid > 0.23e6) {
                            return 0.5706967827806866e18; // 90,000,000, 0.25
                        } else {
                            return 0.5910297971598633e18; // 90,000,000, 0.23
                        }
                    }
                } else {
                    if (recapPercentPaid > 0.17e6) {
                        if (recapPercentPaid > 0.19e6) {
                            return 0.6128602937515535e18; // 90,000,000, 0.21
                        } else {
                            return 0.6363596297698088e18; // 90,000,000, 0.19
                        }
                    } else if (recapPercentPaid > 0.14e6) {
                        if (recapPercentPaid > 0.15e6) {
                            return 0.6617262928282552e18; // 90,000,000, 0.17
                        } else {
                            return 0.6891914824733962e18; // 90,000,000, 0.15
                        }
                    } else if (recapPercentPaid > 0.12e6) {
                        if (recapPercentPaid > 0.13e6) {
                            return 0.7037939098015373e18; // 90,000,000, 0.14
                        } else {
                            return 0.719026126689054e18; // 90,000,000, 0.13
                        }
                    } else {
                        if (recapPercentPaid > 0.11e6) {
                            return 0.7349296649399273e18; // 90,000,000, 0.12
                        } else {
                            return 0.7515497824365694e18; // 90,000,000, 0.11
                        }
                    }
                }
            } else {
                if (recapPercentPaid > 0.08e6) {
                    if (recapPercentPaid > 0.09e6) {
                        return 0.7689358898389307e18; // 90,000,000, 0.1
                    } else {
                        return 0.7871420372030031e18; // 90,000,000, 0.09
                    }
                } else if (recapPercentPaid > 0.06e6) {
                    if (recapPercentPaid > 0.07e6) {
                        return 0.8062274705566613e18; // 90,000,000, 0.08
                    } else {
                        return 0.8262572704372576e18; // 90,000,000, 0.07
                    }
                } else if (recapPercentPaid > 0.05e6) {
                    if (recapPercentPaid > 0.055e6) {
                        return 0.8473030868055568e18; // 90,000,000, 0.06
                    } else {
                        return 0.8582313943058512e18; // 90,000,000, 0.055
                    }
                } else if (recapPercentPaid > 0.04e6) {
                    if (recapPercentPaid > 0.045e6) {
                        return 0.8694439877186144e18; // 90,000,000, 0.05
                    } else {
                        return 0.8809520709014887e18; // 90,000,000, 0.045
                    }
                }
                if (recapPercentPaid > 0.03e6) {
                    if (recapPercentPaid > 0.035e6) {
                        return 0.892767442816813e18; // 90,000,000, 0.04
                    } else {
                        return 0.9049025374937268e18; // 90,000,000, 0.035
                    }
                } else if (recapPercentPaid > 0.02e6) {
                    if (recapPercentPaid > 0.025e6) {
                        return 0.9173704672485867e18; // 90,000,000, 0.03
                    } else {
                        return 0.9301850694774185e18; // 90,000,000, 0.025
                    }
                } else if (recapPercentPaid > 0.01e6) {
                    if (recapPercentPaid > 0.015e6) {
                        return 0.9433609573691148e18; // 90,000,000, 0.02
                    } else {
                        return 0.9569135749274008e18; // 90,000,000, 0.015
                    }
                } else {
                    if (recapPercentPaid > 0.005e6) {
                        return 0.9708592567341514e18; // 90,000,000, 0.01
                    } else {
                        return 0.9852152929368606e18; // 90,000,000, 0.005
                    }
                }
            }
        } else if (unripeSupply > 10_000_000) {
            if (recapPercentPaid > 0.1e6) {
                if (recapPercentPaid > 0.21e6) {
                    if (recapPercentPaid > 0.38e6) {
                        if (recapPercentPaid > 0.45e6) {
                            return 0.2601562129458128e18; // 10,000,000, 0.9
                        } else {
                            return 0.41636482361397587e18; // 10,000,000, 0.45
                        }
                    } else if (recapPercentPaid > 0.29e6) {
                        if (recapPercentPaid > 0.33e6) {
                            return 0.4587658967980477e18; // 10,000,000, 0.38
                        } else {
                            return 0.49461012289361284e18; // 10,000,000, 0.33
                        }
                    } else if (recapPercentPaid > 0.25e6) {
                        if (recapPercentPaid > 0.27e6) {
                            return 0.5274727741119862e18; // 10,000,000, 0.29
                        } else {
                            return 0.5455524222086705e18; // 10,000,000, 0.27
                        }
                    } else {
                        if (recapPercentPaid > 0.23e6) {
                            return 0.5648800673771895e18; // 10,000,000, 0.25
                        } else {
                            return 0.5855868704094357e18; // 10,000,000, 0.23
                        }
                    }
                } else {
                    if (recapPercentPaid > 0.17e6) {
                        if (recapPercentPaid > 0.19e6) {
                            return 0.6078227259058706e18; // 10,000,000, 0.21
                        } else {
                            return 0.631759681239449e18; // 10,000,000, 0.19
                        }
                    } else if (recapPercentPaid > 0.14e6) {
                        if (recapPercentPaid > 0.15e6) {
                            return 0.6575961226208655e18; // 10,000,000, 0.17
                        } else {
                            return 0.68556193437231e18; // 10,000,000, 0.15
                        }
                    } else if (recapPercentPaid > 0.12e6) {
                        if (recapPercentPaid > 0.13e6) {
                            return 0.7004253506676488e18; // 10,000,000, 0.14
                        } else {
                            return 0.7159249025906607e18; // 10,000,000, 0.13
                        }
                    } else {
                        if (recapPercentPaid > 0.11e6) {
                            return 0.7321012978270447e18; // 10,000,000, 0.12
                        } else {
                            return 0.7489987232590216e18; // 10,000,000, 0.11
                        }
                    }
                }
            } else {
                if (recapPercentPaid > 0.08e6) {
                    if (recapPercentPaid > 0.09e6) {
                        return 0.766665218442354e18; // 10,000,000, 0.1
                    } else {
                        return 0.7851530975272665e18; // 10,000,000, 0.09
                    }
                } else if (recapPercentPaid > 0.06e6) {
                    if (recapPercentPaid > 0.07e6) {
                        return 0.8045194270172396e18; // 10,000,000, 0.08
                    } else {
                        return 0.8248265680621683e18; // 10,000,000, 0.07
                    }
                } else if (recapPercentPaid > 0.05e6) {
                    if (recapPercentPaid > 0.055e6) {
                        return 0.8461427935458878e18; // 10,000,000, 0.06
                    } else {
                        return 0.8572024359670631e18; // 10,000,000, 0.055
                    }
                } else if (recapPercentPaid > 0.04e6) {
                    if (recapPercentPaid > 0.045e6) {
                        return 0.8685429921113414e18; // 10,000,000, 0.05
                    } else {
                        return 0.8801749888510111e18; // 10,000,000, 0.045
                    }
                }
                if (recapPercentPaid > 0.03e6) {
                    if (recapPercentPaid > 0.035e6) {
                        return 0.8921094735432339e18; // 10,000,000, 0.04
                    } else {
                        return 0.9043580459814082e18; // 10,000,000, 0.035
                    }
                } else if (recapPercentPaid > 0.02e6) {
                    if (recapPercentPaid > 0.025e6) {
                        return 0.9169328926903124e18; // 10,000,000, 0.03
                    } else {
                        return 0.9298468237651341e18; // 10,000,000, 0.025
                    }
                } else if (recapPercentPaid > 0.01e6) {
                    if (recapPercentPaid > 0.015e6) {
                        return 0.9431133124739901e18; // 10,000,000, 0.02
                    } else {
                        return 0.956746537865208e18; // 10,000,000, 0.015
                    }
                } else {
                    if (recapPercentPaid > 0.005e6) {
                        return 0.970761430644659e18; // 10,000,000, 0.01
                    } else {
                        return 0.9851737226151924e18; // 10,000,000, 0.005
                    }
                }
            }
        } else if (unripeSupply > 1_000_000) {
            if (recapPercentPaid > 0.1e6) {
                if (recapPercentPaid > 0.21e6) {
                    if (recapPercentPaid > 0.38e6) {
                        if (recapPercentPaid > 0.45e6) {
                            return 0.22204456672314377e18; // 1,000,000, 0.9
                        } else {
                            return 0.4085047499499631e18; // 1,000,000, 0.45
                        }
                    } else if (recapPercentPaid > 0.29e6) {
                        if (recapPercentPaid > 0.33e6) {
                            return 0.46027376814120946e18; // 1,000,000, 0.38
                        } else {
                            return 0.5034753937446597e18; // 1,000,000, 0.33
                        }
                    } else if (recapPercentPaid > 0.25e6) {
                        if (recapPercentPaid > 0.27e6) {
                            return 0.5424140302842413e18; // 1,000,000, 0.29
                        } else {
                            return 0.5635119158156667e18; // 1,000,000, 0.27
                        }
                    } else {
                        if (recapPercentPaid > 0.23e6) {
                            return 0.5857864256253713e18; // 1,000,000, 0.25
                        } else {
                            return 0.6093112868361505e18; // 1,000,000, 0.23
                        }
                    }
                } else {
                    if (recapPercentPaid > 0.17e6) {
                        if (recapPercentPaid > 0.19e6) {
                            return 0.6341650041820726e18; // 1,000,000, 0.21
                        } else {
                            return 0.6604311671564058e18; // 1,000,000, 0.19
                        }
                    } else if (recapPercentPaid > 0.14e6) {
                        if (recapPercentPaid > 0.15e6) {
                            return 0.6881987762208012e18; // 1,000,000, 0.17
                        } else {
                            return 0.7175625891924777e18; // 1,000,000, 0.15
                        }
                    } else if (recapPercentPaid > 0.12e6) {
                        if (recapPercentPaid > 0.13e6) {
                            return 0.7328743482797107e18; // 1,000,000, 0.14
                        } else {
                            return 0.7486234889866461e18; // 1,000,000, 0.13
                        }
                    } else {
                        if (recapPercentPaid > 0.11e6) {
                            return 0.7648236427602255e18; // 1,000,000, 0.12
                        } else {
                            return 0.7814888739548376e18; // 1,000,000, 0.11
                        }
                    }
                }
            } else {
                if (recapPercentPaid > 0.08e6) {
                    if (recapPercentPaid > 0.09e6) {
                        return 0.798633693358723e18; // 1,000,000, 0.1
                    } else {
                        return 0.8162730721263407e18; // 1,000,000, 0.09
                    }
                } else if (recapPercentPaid > 0.06e6) {
                    if (recapPercentPaid > 0.07e6) {
                        return 0.8344224561281671e18; // 1,000,000, 0.08
                    } else {
                        return 0.8530977807297004e18; // 1,000,000, 0.07
                    }
                } else if (recapPercentPaid > 0.05e6) {
                    if (recapPercentPaid > 0.055e6) {
                        return 0.8723154860117406e18; // 1,000,000, 0.06
                    } else {
                        return 0.8821330107890434e18; // 1,000,000, 0.055
                    }
                } else if (recapPercentPaid > 0.04e6) {
                    if (recapPercentPaid > 0.045e6) {
                        return 0.8920925324443344e18; // 1,000,000, 0.05
                    } else {
                        return 0.9021962549951718e18; // 1,000,000, 0.045
                    }
                }
                if (recapPercentPaid > 0.03e6) {
                    if (recapPercentPaid > 0.035e6) {
                        return 0.9124464170270961e18; // 1,000,000, 0.04
                    } else {
                        return 0.9228452922244391e18; // 1,000,000, 0.035
                    }
                } else if (recapPercentPaid > 0.02e6) {
                    if (recapPercentPaid > 0.025e6) {
                        return 0.9333951899089395e18; // 1,000,000, 0.03
                    } else {
                        return 0.9440984555862713e18; // 1,000,000, 0.025
                    }
                } else if (recapPercentPaid > 0.01e6) {
                    if (recapPercentPaid > 0.015e6) {
                        return 0.9549574715005937e18; // 1,000,000, 0.02
                    } else {
                        return 0.9659746571972349e18; // 1,000,000, 0.015
                    }
                } else {
                    if (recapPercentPaid > 0.005e6) {
                        return 0.9771524700936202e18; // 1,000,000, 0.01
                    } else {
                        return 0.988493406058558e18; // 1,000,000, 0.005
                    }
                }
            }
        }
    }
}

File 46 of 82 : IDiamondCut.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;
/******************************************************************************\
* 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);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;
// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
    /// These functions are expected to be called frequently
    /// by tools.

    struct Facet {
        address facetAddress;
        bytes4[] functionSelectors;
    }

    /// @notice Gets all facet addresses and their four byte function selectors.
    /// @return facets_ Facet
    function facets() external view returns (Facet[] memory facets_);

    /// @notice Gets all the function selectors supported by a specific facet.
    /// @param _facet The facet address.
    /// @return facetFunctionSelectors_
    function facetFunctionSelectors(
        address _facet
    ) external view returns (bytes4[] memory facetFunctionSelectors_);

    /// @notice Get all the facet addresses used by a diamond.
    /// @return facetAddresses_
    function facetAddresses() external view returns (address[] memory facetAddresses_);

    /// @notice Gets the facet that supports the given selector.
    /// @dev If facet is not found return address(0).
    /// @param _functionSelector The function selector.
    /// @return facetAddress_ The facet address.
    function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @title ICumulativePump
 * @notice Provides an interface for Pumps which calculate time-weighted average
 * reserves through the use of a cumulative reserve.
 */
interface ICumulativePump {
    /**
     * @notice Reads the current cumulative reserves from the Pump
     * @param well The address of the Well
     * @param data data specific to the Well
     * @return cumulativeReserves The cumulative reserves from the Pump
     */
    function readCumulativeReserves(
        address well,
        bytes memory data
    ) external view returns (bytes memory cumulativeReserves);

    /**
     * @notice Reads the current cumulative reserves from the Pump
     * @param well The address of the Well
     * @param startCumulativeReserves The cumulative reserves to start the TWA from
     * @param startTimestamp The timestamp to start the TWA from
     * @param data data specific to the Well
     * @return twaReserves The time weighted average reserves from start timestamp to now
     * @return cumulativeReserves The current cumulative reserves from the Pump at the current timestamp
     */
    function readTwaReserves(
        address well,
        bytes calldata startCumulativeReserves,
        uint startTimestamp,
        bytes memory data
    ) external view returns (uint[] memory twaReserves, bytes memory cumulativeReserves);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

/**
 * @title IMultiFlowPumpWellFunction
 * @dev A Well Function must implement IMultiFlowPumpWellFunction to be supported by
 * the Multi Flow Pump.
 */
interface IMultiFlowPumpWellFunction is IWellFunction {
    /**
     * @notice Calculates the `j` reserve such that `π_{i | i != j} (d reserves_j / d reserves_i) = π_{i | i != j}(ratios_j / ratios_i)`.
     * assumes that reserve_j is being swapped for other reserves in the Well.
     * @dev used by Beanstalk to calculate the deltaB every Season
     * @param reserves The reserves of the Well
     * @param j The index of the reserve to solve for
     * @param ratios The ratios of reserves to solve for
     * @param data Well function data provided on every call
     * @return reserve The resulting reserve at the jth index
     */
    function calcReserveAtRatioSwap(
        uint256[] calldata reserves,
        uint256 j,
        uint256[] calldata ratios,
        bytes calldata data
    ) external view returns (uint256 reserve);

    /**
     * @notice Calculates the rate at which j can be exchanged for i.
     * @param reserves The reserves of the Well
     * @param i The index of the token for which the output is being calculated
     * @param j The index of the token for which 1 token is being exchanged
     * @param data Well function data provided on every call
     * @return rate The rate at which j can be exchanged for i
     * @dev should return with 36 decimal precision
     */
    function calcRate(
        uint256[] calldata reserves,
        uint256 i,
        uint256 j,
        bytes calldata data
    ) external view returns (uint256 rate);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {IWellFunction} from "./IWellFunction.sol";
import {IMultiFlowPumpWellFunction} from "./pumps/IMultiFlowPumpWellFunction.sol";

/**
 * @title IBeanstalkWellFunction
 * @notice Defines all necessary functions for Beanstalk to support a Well Function in addition to functions defined in the primary interface.
 * This includes 2 functions to solve for a given reserve value suc that the average price between
 * the given reserve and all other reserves equals the average of the input ratios.
 * `calcReserveAtRatioSwap` assumes the target ratios are reached through executing a swap.
 * `calcReserveAtRatioLiquidity` assumes the target ratios are reached through adding/removing liquidity.
 */
interface IBeanstalkWellFunction is IMultiFlowPumpWellFunction {
    /**
     * @notice Calculates the `j` reserve such that `π_{i | i != j} (d reserves_j / d reserves_i) = π_{i | i != j}(ratios_j / ratios_i)`.
     * assumes that reserve_j is being added or removed in exchange for LP Tokens.
     * @dev used by Beanstalk to calculate the max deltaB that can be converted in/out of a Well.
     * @param reserves The reserves of the Well
     * @param j The index of the reserve to solve for
     * @param ratios The ratios of reserves to solve for
     * @param data Well function data provided on every call
     * @return reserve The resulting reserve at the jth index
     */
    function calcReserveAtRatioLiquidity(
        uint[] calldata reserves,
        uint j,
        uint[] calldata ratios,
        bytes calldata data
    ) external pure returns (uint reserve);
}

/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity ^0.8.20;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {LibUniswapOracleLibrary} from "./LibUniswapOracleLibrary.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

interface IERC20Decimals {
    function decimals() external view returns (uint8);
}

/**
 * @title Uniswap Oracle Library
 * @notice Contains functionalty to read prices from Uniswap V3 pools.
 **/
library LibUniswapOracle {
    // All instantaneous queries of Uniswap Oracles should use a 15 minute lookback.
    uint32 internal constant FIFTEEN_MINUTES = 900;
    uint256 constant PRECISION = 1e6;

    /**
     * @notice Given a tick and a token amount, calculates the amount of token received in exchange
     * @param baseTokenAmount Amount of baseToken to be converted.
     * @param baseToken Address of the ERC20 token contract used as the baseAmount denomination.
     * @param quoteToken Address of the ERC20 token contract used as the quoteAmount denomination.
     * @return price Amount of quoteToken. Value has 6 decimal precision.
     */
    function getTwap(
        uint32 lookback,
        address pool,
        address baseToken,
        address quoteToken,
        uint128 baseTokenAmount
    ) internal view returns (uint256 price) {
        (bool success, int24 tick) = consult(pool, lookback);
        if (!success) return 0;

        price = LibUniswapOracleLibrary.getQuoteAtTick(
            tick,
            baseTokenAmount,
            baseToken,
            quoteToken
        );

        uint256 baseTokenDecimals = IERC20Decimals(baseToken).decimals();
        uint256 quoteTokenDecimals = IERC20Decimals(quoteToken).decimals();
        int256 factor = int256(baseTokenDecimals) - int256(quoteTokenDecimals);

        // decimals are the same. i.e. DAI/WETH
        if (factor == 0) return (price * PRECISION) / (10 ** baseTokenDecimals);

        // scale decimals
        if (factor > 0) {
            price = price * (10 ** uint256(factor));
        } else {
            price = price / (10 ** uint256(-factor));
        }

        // set 1e6 precision
        price = (price * PRECISION) / (10 ** baseTokenDecimals);
    }

    /**
     * @dev A variation of {OracleLibrary.consult} that returns just the arithmetic mean tick and returns 0 on failure
     * instead of reverting if {IUniswapV3Pool.observe} reverts.
     * https://github.com/Uniswap/v3-periphery/blob/51f8871aaef2263c8e8bbf4f3410880b6162cdea/contracts/libraries/OracleLibrary.sol
     */
    function consult(
        address pool,
        uint32 secondsAgo
    ) internal view returns (bool success, int24 arithmeticMeanTick) {
        require(secondsAgo != 0, "BP");

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

        try IUniswapV3Pool(pool).observe(secondsAgos) returns (
            int56[] memory tickCumulatives,
            uint160[] memory
        ) {
            int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
            arithmeticMeanTick = SafeCast.toInt24(
                int256(tickCumulativesDelta / int56(uint56(secondsAgo)))
            );
            // Always round to negative infinity
            if (tickCumulativesDelta < 0 && (tickCumulativesDelta % int56(uint56(secondsAgo)) != 0))
                arithmeticMeanTick--;
            success = true;
        } catch {}
    }
}

/**
 * SPDX-License-Identifier: MIT
 **/

pragma solidity ^0.8.20;

import {C} from "contracts/C.sol";
import {IChainlinkAggregator} from "contracts/interfaces/chainlink/IChainlinkAggregator.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";

/**
 * @title Chainlink Oracle Library
 * @notice Contains functionalty to fetch prices from Chainlink price feeds.
 * @dev currently supports:
 * - ETH/USD price feed
 **/
library LibChainlinkOracle {
    using LibRedundantMath256 for uint256;

    uint256 constant PRECISION = 1e6; // use 6 decimal precision.

    // timeout for Oracles with a 1 hour heartbeat.
    uint256 constant FOUR_HOUR_TIMEOUT = 14400;
    // timeout for Oracles with a 1 day heartbeat.
    uint256 constant FOUR_DAY_TIMEOUT = 345600;

    struct TwapVariables {
        uint256 cumulativePrice;
        uint256 endTimestamp;
        uint256 lastTimestamp;
    }

    /**
     * @dev Returns the TOKEN1/TOKEN2, or TOKEN2/TOKEN1 price with the option of using a TWA lookback.
     * Use `lookback = 0` for the instantaneous price. `lookback > 0` for a TWAP.
     * Use `tokenDecimals = 0` for TOKEN1/TOKEN2 price. `tokenDecimals > 0` for TOKEN2/TOKEN1 price.
     * Return value has 6 decimal precision if using TOKEN1/TOKEN2, and `tokenDecimals` if using TOKEN2/TOKEN1.
     * Returns 0 if `priceAggregatorAddress` is broken or frozen.
     **/
    function getTokenPrice(
        address priceAggregatorAddress,
        uint256 maxTimeout,
        uint256 tokenDecimals,
        uint256 lookback,
        bool isMillion
    ) internal view returns (uint256 price) {
        return
            lookback > 0
                ? getTwap(priceAggregatorAddress, maxTimeout, tokenDecimals, lookback, isMillion)
                : getPrice(priceAggregatorAddress, maxTimeout, tokenDecimals, isMillion);
    }

    function getTokenPrice(
        address priceAggregatorAddress,
        uint256 maxTimeout,
        uint256 tokenDecimals,
        uint256 lookback
    ) internal view returns (uint256 price) {
        return getTokenPrice(priceAggregatorAddress, maxTimeout, tokenDecimals, lookback, false);
    }

    /**
     * @dev Returns the price of a given `priceAggregator`
     * Use `tokenDecimals = 0` for TOKEN1/TOKEN2 price. `tokenDecimals > 0` for TOKEN2/TOKEN1 price
     * where TOKEN1 is the numerator asset and TOKEN2 is the asset the oracle is denominated in.
     * Return value has 6 decimal precision if using TOKEN1/TOKEN2, and `tokenDecimals` if using TOKEN2/TOKEN1.
     * Returns 0 if Chainlink's price feed is broken or frozen.
     **/
    function getPrice(
        address priceAggregatorAddress,
        uint256 maxTimeout,
        uint256 tokenDecimals,
        bool isMillion
    ) internal view returns (uint256 price) {
        IChainlinkAggregator priceAggregator = IChainlinkAggregator(priceAggregatorAddress);
        // First, try to get current decimal precision:
        uint8 decimals;
        try priceAggregator.decimals() returns (uint8 _decimals) {
            // If call to Chainlink succeeds, record the current decimal precision
            decimals = _decimals;
        } catch {
            // If call to Chainlink aggregator reverts, return a price of 0 indicating failure
            return 0;
        }

        // Secondly, try to get latest price data:
        try priceAggregator.latestRoundData() returns (
            uint80 roundId,
            int256 answer,
            uint256 /* startedAt */,
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            // Check for an invalid roundId that is 0
            if (roundId == 0) return 0;
            if (checkForInvalidTimestampOrAnswer(timestamp, answer, block.timestamp, maxTimeout)) {
                return 0;
            }

            // if token decimals is greater than 0, return the TOKEN2/TOKEN1 price instead (i.e invert the price).
            if (tokenDecimals > 0) {
                // if `isMillion` is set, return `MillionTOKEN2/TOKEN1` Price instead
                // (i.e, the amount of TOKEN1 equal to a million of TOKEN2)
                if (isMillion) tokenDecimals = tokenDecimals + 6;
                price = uint256(10 ** (tokenDecimals + decimals)).div(uint256(answer));
            } else {
                // Adjust to 6 decimal precision.
                price = uint256(answer).mul(PRECISION).div(10 ** decimals);
            }
        } catch {
            // If call to Chainlink aggregator reverts, return a price of 0 indicating failure
            return 0;
        }
    }

    /**
     * @dev Returns the TWAP price from the Chainlink Oracle over the past `lookback` seconds.
     * Use `tokenDecimals = 0` for TOKEN1/TOKEN2 price. `tokenDecimals > 0` for TOKEN2/TOKEN1 price.
     * Return value has 6 decimal precision if using TOKEN1/TOKEN2, and `tokenDecimals` if using TOKEN2/TOKEN1.
     * Returns 0 if Chainlink's price feed is broken or frozen.
     **/
    function getTwap(
        address priceAggregatorAddress,
        uint256 maxTimeout,
        uint256 tokenDecimals,
        uint256 lookback,
        bool isMillion
    ) internal view returns (uint256 price) {
        // First, try to get current decimal precision:
        uint8 decimals;
        try IChainlinkAggregator(priceAggregatorAddress).decimals() returns (uint8 _decimals) {
            // If call to Chainlink succeeds, record the current decimal precision
            decimals = _decimals;
        } catch {
            // If call to Chainlink aggregator reverts, return a price of 0 indicating failure
            return 0;
        }

        // Secondly, try to get latest price data:
        try IChainlinkAggregator(priceAggregatorAddress).latestRoundData() returns (
            uint80 roundId,
            int256 answer,
            uint256 /* startedAt */,
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            // Check for an invalid roundId that is 0
            if (roundId == 0) return 0;
            if (checkForInvalidTimestampOrAnswer(timestamp, answer, block.timestamp, maxTimeout)) {
                return 0;
            }

            TwapVariables memory t;

            t.endTimestamp = block.timestamp.sub(lookback);

            if (isMillion) {
                // if `isMillion` flag is enabled,
                tokenDecimals = tokenDecimals + 6;
            }
            // Check if last round was more than `lookback` ago.
            if (timestamp <= t.endTimestamp) {
                if (tokenDecimals > 0) {
                    return uint256(10 ** (tokenDecimals + decimals)).div(uint256(answer));
                } else {
                    // Adjust to 6 decimal precision.
                    return uint256(answer).mul(PRECISION).div(10 ** decimals);
                }
            } else {
                t.lastTimestamp = block.timestamp;
                // Loop through previous rounds and compute cumulative sum until
                // a round at least `lookback` seconds ago is reached.
                while (timestamp > t.endTimestamp) {
                    // if token decimals is greater than 0, return the TOKEN2/TOKEN1 price instead (i.e invert the price).
                    if (tokenDecimals > 0) {
                        answer = int256((10 ** (tokenDecimals + decimals)) / (uint256(answer)));
                    }
                    t.cumulativePrice = t.cumulativePrice.add(
                        uint256(answer).mul(t.lastTimestamp.sub(timestamp))
                    );
                    roundId -= 1;
                    t.lastTimestamp = timestamp;
                    (answer, timestamp) = getRoundData(
                        IChainlinkAggregator(priceAggregatorAddress),
                        roundId
                    );
                    if (
                        checkForInvalidTimestampOrAnswer(
                            timestamp,
                            answer,
                            t.lastTimestamp,
                            maxTimeout
                        )
                    ) {
                        return 0;
                    }
                }
                if (tokenDecimals > 0) {
                    answer = int256((10 ** (tokenDecimals + decimals)) / (uint256(answer)));
                }
                t.cumulativePrice = t.cumulativePrice.add(
                    uint256(answer).mul(t.lastTimestamp.sub(t.endTimestamp))
                );
                if (tokenDecimals > 0) {
                    price = t.cumulativePrice.div(lookback);
                } else {
                    price = t.cumulativePrice.mul(PRECISION).div(10 ** decimals).div(lookback);
                }
            }
        } catch {
            // If call to Chainlink aggregator reverts, return a price of 0 indicating failure
            return 0;
        }
    }

    function getRoundData(
        IChainlinkAggregator priceAggregator,
        uint80 roundId
    ) private view returns (int256, uint256) {
        try priceAggregator.getRoundData(roundId) returns (
            uint80 /* roundId */,
            int256 _answer,
            uint256 /* startedAt */,
            uint256 _timestamp,
            uint80 /* answeredInRound */
        ) {
            return (_answer, _timestamp);
        } catch {
            return (-1, 0);
        }
    }

    function checkForInvalidTimestampOrAnswer(
        uint256 timestamp,
        int256 answer,
        uint256 currentTimestamp,
        uint256 maxTimeout
    ) private pure returns (bool) {
        // Check for an invalid timeStamp that is 0, or in the future
        if (timestamp == 0 || timestamp > currentTimestamp) return true;
        // Check if Chainlink's price feed has timed out
        if (currentTimestamp.sub(timestamp) > maxTimeout) return true;
        // Check for non-positive price
        if (answer <= 0) return true;

        return false;
    }
}

File 55 of 82 : IUniswapV3Pool.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IUniswapV3PoolImmutables} from './pool/IUniswapV3PoolImmutables.sol';
import {IUniswapV3PoolState} from './pool/IUniswapV3PoolState.sol';
import {IUniswapV3PoolDerivedState} from './pool/IUniswapV3PoolDerivedState.sol';
import {IUniswapV3PoolActions} from './pool/IUniswapV3PoolActions.sol';
import {IUniswapV3PoolOwnerActions} from './pool/IUniswapV3PoolOwnerActions.sol';
import {IUniswapV3PoolErrors} from './pool/IUniswapV3PoolErrors.sol';
import {IUniswapV3PoolEvents} from './pool/IUniswapV3PoolEvents.sol';

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

}

File 56 of 82 : System.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

/**
 * @title System
 * @notice Stores system-level Beanstalk state.
 * @param paused True if Beanstalk is Paused.
 * @param pausedAt The timestamp at which Beanstalk was last paused.
 * @param reentrantStatus An intra-transaction state variable to protect against reentrance.
 * @param farmingStatus Stores whether the function call originated in a Farm-like transaction - Farm, Tractor, PipelineConvert, etc.
 * @param ownerCandidate Stores a candidate address to transfer ownership to. The owner must claim the ownership transfer.
 * @param plenty The amount of plenty token held by the contract.
 * @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.calcCaseId}.
 * @param activeField ID of the active Field.
 * @param fieldCount Number of Fields that have ever been initialized.
 * @param orderLockedBeans The number of Beans locked in Pod Orders.
 * @param _buffer_0 Reserved storage for future additions.
 * @param podListings A mapping from fieldId to index to hash of 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 internalTokenBalanceTotal Sum of all users internalTokenBalance.
 * @param wellOracleSnapshots A mapping from Well Oracle address to the Well Oracle Snapshot.
 * @param twaReserves A mapping from well to its twaReserves. Stores twaReserves during the sunrise function. Returns 1 otherwise for each asset. Currently supports 2 token wells.
 * @param usdTokenPrice A mapping from token address to usd price.
 * @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 fields mapping of Field ID to Storage.Field.
 * @param convertCapacity A mapping from block number to the amount of Beans that can be converted towards peg in this block before stalk penalty becomes applied.
 * @param oracleImplementation A mapping from token to its oracle implementation.
 * @param shipmentRoutes Define the distribution of newly minted Beans.
 * @param _buffer_1 Reserved storage for future additions.
 * @param casesV2 Stores the 144 Weather and seedGauge cases.
 * @param silo See {Silo}.
 * @param fert See {Fertilizer}.
 * @param season See {Season}.
 * @param weather See {Weather}.
 * @param seedGauge Stores the seedGauge.
 * @param rain See {Rain}.
 * @param migration See {Migration}.
 * @param evaluationParameters See {EvaluationParameters}.
 * @param sop See {SeasonOfPlenty}.
 */
struct System {
    bool paused;
    uint128 pausedAt;
    uint256 reentrantStatus;
    uint256 farmingStatus;
    address ownerCandidate;
    uint128 soil;
    uint128 beanSown;
    uint256 activeField;
    uint256 fieldCount;
    uint256 orderLockedBeans;
    bytes32[16] _buffer_0;
    mapping(uint256 => mapping(uint256 => bytes32)) podListings;
    mapping(bytes32 => uint256) podOrders;
    mapping(IERC20 => uint256) internalTokenBalanceTotal;
    mapping(address => bytes) wellOracleSnapshots;
    mapping(address => TwaReserves) twaReserves;
    mapping(address => uint256) usdTokenPrice;
    mapping(uint256 => Field) fields;
    mapping(uint256 => ConvertCapacity) convertCapacity;
    mapping(address => Implementation) oracleImplementation;
    ShipmentRoute[] shipmentRoutes;
    bytes32[16] _buffer_1;
    bytes32[144] casesV2;
    Tokens tokens;
    Silo silo;
    Fertilizer fert;
    Season season;
    Weather weather;
    SeedGauge seedGauge;
    Rain rain;
    L2Migration l2Migration;
    EvaluationParameters evaluationParameters;
    SeasonOfPlenty sop;
    // A buffer is not included here, bc current layout of AppStorage makes it unnecessary.
}

/**
 * @notice Tokens used in the Beanstalk system.
 * @param bean Beanstalk ERC-20 fiat stablecoin
 * @param fertilizer Fertilizer ERC-1555 token
 * @param urBean Unripe Bean issud to Bean holders at the time of the exploit.
 * @param urLp Unripe LP issued to LP holders at the time of the exploit.
 */
struct Tokens {
    address bean;
    address fertilizer;
    address urBean;
    address urLp;
}

/**
 * @notice System-level Silo state variables.
 * @param stalk The total amount of active Stalk (including Earned Stalk, excluding Grown Stalk).
 * @param roots The total amount of Roots.
 * @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 balances A mapping from Token address to Silo Balance storage (amount deposited and withdrawn).
 * @param assetSettings A mapping from Token address to Silo Settings for each Whitelisted Token. If a non-zero storage exists, a Token is whitelisted.
 * @param unripeSettings 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 whitelistStatuses Stores a list of Whitelist Statues for all tokens that have been Whitelisted and have not had their Whitelist Status manually removed.
 * @param germinating Mapping from odd/even to token to germinating deposits data.
 * @param unclaimedGerminating A mapping from season to object containing the stalk and roots that are germinating.
 * @param _buffer Reserved storage for future expansion.
 */
struct Silo {
    uint256 stalk;
    uint256 roots;
    uint256 earnedBeans;
    mapping(address => AssetSilo) balances;
    mapping(address => AssetSettings) assetSettings;
    mapping(address => UnripeSettings) unripeSettings;
    WhitelistStatus[] whitelistStatuses;
    mapping(GerminationSide => mapping(address => Deposited)) germinating;
    mapping(uint32 => GerminatingSilo) unclaimedGerminating;
    bytes32[8] _buffer;
}

/**
 * @notice System-level Field state variables.
 * @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.
 * @param _buffer Reserved storage for future expansion.
 */
struct Field {
    uint256 pods;
    uint256 harvested;
    uint256 harvestable;
    bytes32[8] _buffer;
}

/**
 * @notice Fertilizer data.
 * @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 fertilizedPaidIndex The total number of Fertilizer Beans that have been sent out to users.
 * @param fertFirst The lowest active Fertilizer Id (start of linked list that is stored by nextFid).
 * @param fertLast The highest active Fertilizer Id (end of linked list that is stored by nextFid).
 * @param bpf The cumulative Beans Per Fertilizer (bfp) minted over all Season.
 * @param recapitalized The number of USDC that has been recapitalized in the Barn Raise.
 * @param leftoverBeans Amount of Beans that have shipped to Fert but not yet reflected in bpf.
 * @param _buffer Reserved storage for future expansion.
 */
struct Fertilizer {
    mapping(uint128 => uint256) fertilizer;
    mapping(uint128 => uint128) nextFid;
    uint256 activeFertilizer;
    uint256 fertilizedIndex;
    uint256 unfertilizedIndex;
    uint256 fertilizedPaidIndex;
    uint128 fertFirst;
    uint128 fertLast;
    uint128 bpf;
    uint256 recapitalized;
    uint256 leftoverBeans;
    bytes32[8] _buffer;
}

/**
 * @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 stemScaleSeason // season in which the stem v1.1 was introduced, where stems are not truncated anymore.
 * @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.
 * @param _buffer Reserved storage for future expansion.
 */
struct Season {
    uint32 current;
    uint32 lastSop;
    uint8 withdrawSeasons;
    uint32 lastSopSeason;
    uint32 rainStart;
    bool raining;
    bool fertilizing;
    uint32 sunriseBlock;
    bool abovePeg;
    uint16 stemStartSeason;
    uint16 stemScaleSeason;
    uint256 start;
    uint256 period;
    uint256 timestamp;
    bytes32[8] _buffer;
}

/**
 * @notice System-level Weather state variables.
 * @param lastDeltaSoil 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 temp Temperature is max interest rate in current Season for sowing Beans in Soil. Adjusted each Season.
 * @param _buffer Reserved storage for future expansion.
 */
struct Weather {
    uint128 lastDeltaSoil; // ───┐ 16 (16)
    uint32 lastSowTime; //       │ 4  (20)
    uint32 thisSowTime; //       │ 4  (24)
    uint32 temp; // ─────────────┘ 4  (28/32)
    bytes32[4] _buffer;
}

/**
 * @notice System level variables used in the seed Gauge
 * @param averageGrownStalkPerBdvPerSeason The average Grown Stalk Per BDV
 * that beanstalk issues each season.
 * @param beanToMaxLpGpPerBdvRatio a scalar of the gauge points(GP) per bdv
 * issued to the largest LP share and Bean. 6 decimal precision.
 * @param _buffer Reserved storage for future expansion.
 * @dev a beanToMaxLpGpPerBdvRatio of 0 means LP should be incentivized the most,
 * and that beans will have the minimum seeds ratio. see {LibGauge.getBeanToMaxLpGpPerBdvRatioScaled}
 */
struct SeedGauge {
    uint128 averageGrownStalkPerBdvPerSeason;
    uint128 beanToMaxLpGpPerBdvRatio;
    bytes32[4] _buffer;
}

/**
 * @notice System-level Rain balances. Rain occurs when P > 1 and the Pod Rate Excessively Low.
 * @param pods The number of Pods when it last started Raining.
 * @param roots The number of Roots when it last started Raining.
 * @param _buffer Reserved storage for future expansion.
 */
struct Rain {
    uint256 pods;
    uint256 roots;
    bytes32[4] _buffer;
}

/**
 * @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.
 * @dev {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.
 */
struct AssetSilo {
    uint128 deposited;
    uint128 depositedBdv;
}

/**
 * @notice Whitelist Status a token that has been Whitelisted before.
 * @param token the address of the token.
 * @param isWhitelisted whether the address is whitelisted.
 * @param isWhitelistedLp whether the address is a whitelisted LP token.
 * @param isWhitelistedWell whether the address is a whitelisted Well token.
 */

struct WhitelistStatus {
    address token;
    bool isWhitelisted;
    bool isWhitelistedLp;
    bool isWhitelistedWell;
    bool isSoppable;
}

/**
 * @notice Describes the settings for each Token that is Whitelisted in the Silo.
 * @param selector The encoded BDV function selector for the token that pertains to
 * an external view Beanstalk function with the following signature:
 * ```
 * function tokenToBdv(uint256 amount) external view returns (uint256);
 * ```
 * It is called by `LibTokenSilo` through the use of `delegatecall`
 * to calculate a token's BDV at the time of Deposit.
 * @param stalkEarnedPerSeason represents how much Stalk one BDV of the underlying deposited token
 * grows each season. In the past, this was represented by seeds. 6 decimal precision.
 * @param stalkIssuedPerBdv The Stalk Per BDV that the Silo grants in exchange for Depositing this Token.
 * previously called stalk.
 * @param milestoneSeason The last season in which the stalkEarnedPerSeason for this token was updated.
 * @param milestoneStem The cumulative amount of grown stalk per BDV for this token at the last stalkEarnedPerSeason update.
 * @param encodeType determine the encoding type of the selector.
 * a encodeType of 0x00 means the selector takes an input amount.
 * 0x01 means the selector takes an input amount and a token.
 * @param gpSelector The encoded gaugePoint function selector for the token that pertains to
 * an external view Beanstalk function with the following signature:
 * ```
 * function gaugePoints(
 *  uint256 currentGaugePoints,
 *  uint256 optimalPercentDepositedBdv,
 *  uint256 percentOfDepositedBdv
 *  ) external view returns (uint256);
 * ```
 * @param lwSelector The encoded liquidityWeight function selector for the token that pertains to
 * an external view Beanstalk function with the following signature `function liquidityWeight()`
 * @param gaugePoints the amount of Gauge points this LP token has in the LP Gauge. Only used for LP whitelisted assets.
 * GaugePoints has 18 decimal point precision (1 Gauge point = 1e18).
 * @param optimalPercentDepositedBdv The target percentage of the total LP deposited BDV for this token. 6 decimal precision.
 * @param gaugePointImplementation The implementation for the gauge points. Supports encodeType 0 and 1.
 * @param liquidityWeightImplementation The implementation for the liquidity weight.
 * @dev A Token is considered Whitelisted if there exists a non-zero {AssetSettings} selector.
 */
struct AssetSettings {
    bytes4 selector; // ────────────────────┐ 4
    uint32 stalkEarnedPerSeason; //         │ 4  (8)
    uint48 stalkIssuedPerBdv; //            │ 6  (14)
    uint32 milestoneSeason; //              │ 4  (18)
    int96 milestoneStem; //                 │ 12 (30)
    bytes1 encodeType; //                   │ 1  (31)
    // one byte is left here.             ──┘ 1  (32)
    int32 deltaStalkEarnedPerSeason; // ────┐ 4
    uint128 gaugePoints; //                 │ 16 (20)
    uint64 optimalPercentDepositedBdv; //   │ 8  (28)
    // 4 bytes are left here.             ──┘ 4  (32)
    Implementation gaugePointImplementation;
    Implementation liquidityWeightImplementation;
}

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

/**
 * @notice Stores the twaReserves for each well during the sunrise function.
 */
struct TwaReserves {
    uint128 reserve0;
    uint128 reserve1;
}

/**
 * @notice Stores the total germination amounts for each whitelisted token.
 */
struct Deposited {
    uint128 amount;
    uint128 bdv;
}

struct ConvertCapacity {
    uint256 overallConvertCapacityUsed;
    mapping(address => uint256) wellConvertCapacityUsed;
}

/**
 * @notice Stores the system level germination Silo data.
 */
struct GerminatingSilo {
    uint256 stalk;
    uint256 roots;
}

/**
 * @param planContract The address of the contract containing the plan getter view function.
 * @param planSelector The selector of the plan getter view function.
 * @param recipient The recipient enum of the shipment.
 * @param data The data to be passed to both the plan getter function and the receive function.
 */
struct ShipmentRoute {
    address planContract;
    bytes4 planSelector;
    ShipmentRecipient recipient;
    bytes data;
}

/**
 * @notice storage relating to the L2 Migration. Can be removed upon a full migration.
 * @param migratedL1Beans the amount of L1 Beans that have been migrated to L2.
 * @param contractata a mapping from a L1 contract to an approved L2 reciever.
 * @param _buffer_ Reserved storage for future additions.
 */
struct L2Migration {
    uint256 migratedL1Beans;
    mapping(address => MigrationData) account;
    bytes32[4] _buffer_;
}

/**
 * @notice contains data relating to migration.
 */
struct MigrationData {
    address reciever;
    bool migratedDeposits;
    bool migratedPlots;
    bool migratedFert;
    bool migratedInternalBalances;
    bool migratedPodOrders;
}

/**
 * @notice contains data in order for beanstalk to call a function with a specific selector.
 * @param target The address of the implementation.
 * @param selector The function selector that is used to call on the implementation.
 * @param encodeType The encode type that should be used to encode the function call.
 * The encodeType value depends on the context of each implementation.
 * @param data Any additional data, for example timeout
 * @dev assumes all future implementations will use the same parameters as the beanstalk
 * gaugePoint and liquidityWeight implementations.
 */
struct Implementation {
    address target; // 20 bytes
    bytes4 selector;
    bytes1 encodeType;
    bytes data;
}

struct EvaluationParameters {
    uint256 maxBeanMaxLpGpPerBdvRatio;
    uint256 minBeanMaxLpGpPerBdvRatio;
    uint256 targetSeasonsToCatchUp;
    uint256 podRateLowerBound;
    uint256 podRateOptimal;
    uint256 podRateUpperBound;
    uint256 deltaPodDemandLowerBound;
    uint256 deltaPodDemandUpperBound;
    uint256 lpToSupplyRatioUpperBound;
    uint256 lpToSupplyRatioOptimal;
    uint256 lpToSupplyRatioLowerBound;
    uint256 excessivePriceThreshold;
    uint256 soilCoefficientHigh;
    uint256 soilCoefficientLow;
    uint256 baseReward;
}

/**
 * @param perWellPlenty A mapping from well amount of plenty (flooded tokens) per well
 * @param sops mapping of season to a mapping of wells to plentyPerRoot
 */
struct SeasonOfPlenty {
    mapping(address => uint256) plentyPerSopToken;
    mapping(uint32 => mapping(address => uint256)) sops;
}

/**
 * @notice Germinate determines what germination struct to use.
 * @dev "odd" and "even" refers to the value of the season counter.
 * "Odd" germinations are used when the season is odd, and vice versa.
 */
enum GerminationSide {
    ODD,
    EVEN,
    NOT_GERMINATING
}

/**
 * @notice Details which Beanstalk component receives the shipment.
 */
enum ShipmentRecipient {
    NULL,
    SILO,
    FIELD,
    BARN
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;

import {ERC20} from "../ERC20.sol";
import {Context} from "../../../utils/Context.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)

pragma solidity ^0.8.20;

import {IERC20Permit} from "./IERC20Permit.sol";
import {ERC20} from "../ERC20.sol";
import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
import {EIP712} from "../../../utils/cryptography/EIP712.sol";
import {Nonces} from "../../../utils/Nonces.sol";

/**
 * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
    bytes32 private constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Permit deadline has expired.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Mismatched signature.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    constructor(string memory name) EIP712(name, "1") {}

    /**
     * @inheritdoc IERC20Permit
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        if (block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }

        _approve(owner, spender, value);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
        return super.nonces(owner);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
        return _domainSeparatorV4();
    }
}

File 62 of 82 : Account.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {GerminationSide} from "./System.sol";

/**
 * @title Account
 * @notice Stores Farmer-level Beanstalk state.
 * @param roots A Farmer's Root balance.
 * @param stalk Balance of the Farmer's Stalk.
 * @param depositPermitNonces A Farmer's current deposit permit nonce.
 * @param tokenPermitNonces A Farmer's current token permit nonce.
 * @param lastUpdate The Season in which the Farmer last updated their Silo.
 * @param lastSop The last Season that a SOP occurred 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 _buffer_0 Reserved storage for future additions.
 * @param deposits SiloV3.1 deposits. A mapping from depositId to Deposit. SiloV3.1 introduces greater precision for deposits.
 * @param depositIdList DepositListData for each token owned by the account.
 * @param field A mapping from FieldId to a Farmer's Field storage.
 * @param depositAllowances A mapping of `spender => Silo token address => amount`.
 * @param tokenAllowances Internal balance token allowances.
 * @param mowStatuses A mapping of whitelisted token address to MowStatus.
 * @param isApprovedForAll A mapping of ERC1155 operator to approved status. ERC1155 compatability.
 * @param germinatingStalk A Farmer's germinating stalk. Separated into odd and even stalk.
 * @param internalTokenBalance A mapping from Token address to Internal Balance. It stores the amount of the Token that the Farmer has stored as an Internal Balance in Beanstalk.
 * @param _buffer_1 Reserved storage for future additions.
 * @param silo A Farmer's Silo storage.
 * @param sop A Farmer's Season of Plenty storage.
 */
struct Account {
    uint256 roots;
    uint256 stalk;
    uint256 depositPermitNonces;
    uint256 tokenPermitNonces;
    uint32 lastUpdate;
    uint32 lastSop;
    uint32 lastRain;
    bytes32[16] _buffer_0;
    mapping(uint256 => Deposit) deposits;
    mapping(address => DepositListData) depositIdList;
    mapping(uint256 => Field) fields;
    mapping(address => mapping(address => uint256)) depositAllowances;
    mapping(address => mapping(IERC20 => uint256)) tokenAllowances;
    mapping(address => MowStatus) mowStatuses;
    mapping(address => bool) isApprovedForAll;
    mapping(GerminationSide => uint128) germinatingStalk;
    mapping(IERC20 => uint256) internalTokenBalance;
    bytes32[16] _buffer_1;
    SeasonOfPlenty sop;
}

/**
 * @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.
 * @param plotIndexes An array of Plot indexes. Used to return the farm plots of a Farmer.
 * @param piIndex A mapping from Plot index to the index in plotIndexes.
 * @param _buffer Reserved storage for future additions.
 */
struct Field {
    mapping(uint256 => uint256) plots;
    mapping(address => uint256) podAllowances;
    uint256[] plotIndexes;
    mapping(uint256 => uint256) piIndex;
    bytes32[4] _buffer;
}

/**
 * @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 tokens.
 * @param _buffer Reserved storage for future additions.
 */
struct SeasonOfPlenty {
    uint256 rainRoots; // The number of Roots a Farmer had when it started Raining.
    mapping(address => PerWellPlenty) perWellPlenty; // a mapping from well to plentyPerRoot and plenty.
    bytes32[4] _buffer;
}

/**
 * @notice Stores a Farmer's Season of Plenty (SOP) balances.
 * @param plentyPerRoot The Plenty Per Root index for this well at the last time a Farmer updated their Silo.
 * @param plenty The balance of a Farmer's plenty. Plenty can be claimed directly for the well's non-Bean token.
 */
struct PerWellPlenty {
    uint256 plentyPerRoot;
    uint256 plenty;
    bytes32[4] _buffer;
}

/**
 * @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.
 * @param _buffer Reserved storage for future additions.
 * @dev `amount` and `bdv` are packed as uint128 to save gas.
 */
struct Deposit {
    uint128 amount;
    uint128 bdv;
}

/**
 * @notice Stores a Farmer's germinating stalk.
 * @param odd - stalk from assets deposited in odd seasons.
 * @param even - stalk from assets deposited in even seasons.
 * @param _buffer Reserved storage for future additions.
 */
struct GerminatingStalk {
    uint128 odd;
    uint128 even;
}

/**
 * @notice This struct stores the mow status for each whitelisted 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.
 * @param _buffer Reserved storage for future additions.
 */
struct MowStatus {
    int96 lastStem;
    uint128 bdv;
}

/**
 * @notice This struct stores data for a deposit list for a given token.
 * a mapping from id to index was created to allow for O(1) retrevial of a deposit from the list.
 * @param depositIds An array of depositIds for a given token.
 * @param idIndex A mapping from depositId to index in depositIds.
 */
struct DepositListData {
    uint256[] depositIds;
    mapping(uint256 => uint256) idIndex;
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.9.0;

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

/// @title LibUniswapOracleLibrary
/// @notice Provides functions to integrate with V3 pool oracle
/// @dev forked from: https://github.com/Uniswap/v3-periphery/blob/0.8/contracts/libraries/OracleLibrary.sol,
/// due to node version incompatabilities.
library LibUniswapOracleLibrary {
    /// @notice Calculates time-weighted means of tick and liquidity for a given Uniswap V3 pool
    /// @param pool Address of the pool that we want to observe
    /// @param secondsAgo Number of seconds in the past from which to calculate the time-weighted means
    /// @return arithmeticMeanTick The arithmetic mean tick from (block.timestamp - secondsAgo) to block.timestamp
    /// @return harmonicMeanLiquidity The harmonic mean liquidity from (block.timestamp - secondsAgo) to block.timestamp
    function consult(
        address pool,
        uint32 secondsAgo
    ) internal view returns (int24 arithmeticMeanTick, uint128 harmonicMeanLiquidity) {
        require(secondsAgo != 0, "BP");

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

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

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

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

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

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

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

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

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

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

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

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

        ) = IUniswapV3Pool(pool).slot0();

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

        // If the latest observation occurred in the past, then no tick-changing trades have happened in this block
        // therefore the tick in `slot0` is the same as at the beginning of the current block.
        // We don't need to check if this observation is initialized - it is guaranteed to be.
        (
            uint32 observationTimestamp,
            int56 tickCumulative,
            uint160 secondsPerLiquidityCumulativeX128,

        ) = IUniswapV3Pool(pool).observations(observationIndex);
        if (observationTimestamp != uint32(block.timestamp)) {
            return (tick, IUniswapV3Pool(pool).liquidity());
        }

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

        require(prevInitialized, "ONI");

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

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

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

        // Accumulates the sum of the weights
        uint256 denominator;

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

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

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

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

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

    function version() external view returns (uint256);

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

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

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

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

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

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

File 70 of 82 : IUniswapV3PoolErrors.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Errors emitted by a pool
/// @notice Contains all events emitted by the pool
interface IUniswapV3PoolErrors {
    error LOK();
    error TLU();
    error TLM();
    error TUM();
    error AI();
    error M0();
    error M1();
    error AS();
    error IIA();
    error L();
    error F0();
    error F1();
}

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;

/**
 * @dev Provides tracking nonces for addresses. Nonces will only increment.
 */
abstract contract Nonces {
    /**
     * @dev The nonce used for an `account` is not the expected current nonce.
     */
    error InvalidAccountNonce(address account, uint256 currentNonce);

    mapping(address account => uint256) private _nonces;

    /**
     * @dev Returns the next unused nonce for an address.
     */
    function nonces(address owner) public view virtual returns (uint256) {
        return _nonces[owner];
    }

    /**
     * @dev Consumes a nonce.
     *
     * Returns the current value and increments nonce.
     */
    function _useNonce(address owner) internal virtual returns (uint256) {
        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
        // decremented or reset. This guarantees that the nonce never overflows.
        unchecked {
            // It is important to do x++ and not ++x here.
            return _nonces[owner]++;
        }
    }

    /**
     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
     */
    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
        uint256 current = _useNonce(owner);
        if (nonce != current) {
            revert InvalidAccountNonce(owner, current);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    error T();
    error R();

    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

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

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

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

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

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

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

            uint256 r = ratio;
            uint256 msb = 0;

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

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

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

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

            int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

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

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

File 82 of 82 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@wells/=node_modules/@beanstalk/wells1.1/",
    "@beanstalk/=node_modules/@beanstalk/",
    "@ethereum-waffle/=node_modules/@ethereum-waffle/",
    "@prb/=node_modules/@prb/",
    "@uniswap/=node_modules/@uniswap/",
    "ds-test/=node_modules/@beanstalk/wells/lib/forge-std/lib/ds-test/",
    "erc4626-tests/=node_modules/@beanstalk/wells/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts-upgradeable/=node_modules/@beanstalk/wells/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=node_modules/@beanstalk/wells/lib/openzeppelin-contracts/",
    "prb-math/=node_modules/@beanstalk/wells/lib/prb-math/",
    "prb-test/=node_modules/@beanstalk/wells/lib/prb-math/lib/prb-test/",
    "uniswap/=node_modules/uniswap/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC1155InvalidApprover","type":"error"},{"inputs":[{"internalType":"uint256","name":"idsLength","type":"uint256"},{"internalType":"uint256","name":"valuesLength","type":"uint256"}],"name":"ERC1155InvalidArrayLength","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC1155InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC1155InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC1155InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155MissingApprovalForAll","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"beans","type":"uint256"}],"name":"ClaimFertilizer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfFertilized","outputs":[{"internalType":"uint256","name":"beans","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfUnfertilized","outputs":[{"internalType":"uint256","name":"beans","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"bpf","type":"uint128"}],"name":"beanstalkMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint128","name":"bpf","type":"uint128"}],"name":"beanstalkUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getMintId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint128","name":"bpfRemaining","type":"uint128"}],"name":"imageURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"lastBalanceOf","outputs":[{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"lastBpf","type":"uint128"}],"internalType":"struct Internalizer.Balance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"lastBalanceOfBatch","outputs":[{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"lastBpf","type":"uint128"}],"internalType":"struct Internalizer.Balance[]","name":"balances","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"remaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

6080604052348015600e575f80fd5b50613d008061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610147575f3560e01c80638da5cb5b116100bf578063b6f4208511610079578063b6f42085146102d7578063bf02d309146102ea578063e1c7392a1461030a578063e985e9c514610312578063f242432a14610325578063f2fde38b14610338575f80fd5b80638da5cb5b1461024957806391b7301f1461025e57806395d89b411461027e57806397e6e4671461029e5780639a9a18a2146102b1578063a22cb465146102c4575f80fd5b8063246c0d8711610110578063246c0d87146101e95780632c12865b146101f15780632eb2c2d6146102045780634e1273f41461021957806355234ec014610239578063715018a614610241575f80fd5b8062fdd58e1461014b57806301ffc9a71461017157806306fdde03146101945780630e89341c146101c35780631edb6be1146101d6575b5f80fd5b61015e6101593660046120ce565b61034b565b6040519081526020015b60405180910390f35b61018461017f36600461210b565b6103ac565b6040519015158152602001610168565b60408051808201909152600a8152692332b93a34b634bd32b960b11b60208201525b6040516101689190612173565b6101b66101d1366004612185565b6103fb565b61015e6101e4366004612271565b6104c4565b61015e61061e565b6101b66101ff3660046122cf565b610694565b61021761021236600461236c565b6106af565b005b61022c61022736600461240e565b610888565b6040516101689190612502565b61015e610952565b6102176109bf565b6102516109d2565b6040516101689190612514565b61027161026c3660046120ce565b610a00565b6040516101689190612528565b6040805180820190915260048152631191549560e21b60208201526101b6565b61015e6102ac36600461254c565b610a83565b6102176102bf3660046125a9565b610aa8565b6102176102d23660046125f7565b610b9d565b61015e6102e5366004612271565b610bac565b6102fd6102f836600461240e565b610d40565b6040516101689190612625565b610217610e15565b610184610320366004612687565b610f2e565b6102176103333660046126b8565b610f6b565b610217610346366004612717565b6110a4565b5f6001600160a01b03831661037b5760405162461bcd60e51b815260040161037290612730565b60405180910390fd5b505f818152602081815260408083206001600160a01b03861684529091529020546001600160801b03165b92915050565b5f6001600160e01b03198216636cdb3d1360e11b14806103dc57506001600160e01b031982166303a24d0760e21b145b806103a657506301ffc9a760e01b6001600160e01b03198316146103a6565b60605f610407836110e1565b90505f6104148483610694565b90506040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525061049b610458866111f8565b610461876111f8565b84610474876001600160801b0316611287565b6040516020016104879493929190612796565b604051602081830303815290604052611343565b6040516020016104ac929190612a7d565b60405160208183030381529060405292505050919050565b5f806104ce6109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610509573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052d9190612aab565b6001600160801b031690505f5b8351811015610616578184828151811061055657610556612ac6565b6020026020010151111561060e5761060b6106045f8087858151811061057e5761057e612ac6565b602002602001015181526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f015f9054906101000a90046001600160801b03166001600160801b03166105fe858886815181106105e8576105e8612ac6565b602002602001015161149190919063ffffffff16565b9061149c565b84906114a7565b92505b60010161053a565b505092915050565b5f6106276109d2565b6001600160a01b031663c85951a16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610662573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106869190612aab565b6001600160801b0316905090565b60606106a86106a384846114b2565b611532565b9392505050565b81518351146107115760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610372565b6001600160a01b0384166107375760405162461bcd60e51b815260040161037290612ada565b6001600160a01b03851633148061075357506107538533610f2e565b6107ba5760405162461bcd60e51b815260206004820152603260248201527f455243313135353a207472616e736665722063616c6c6572206973206e6f74206044820152711bdddb995c881b9bdc88185c1c1c9bdd995960721b6064820152608401610372565b336107c981878787878761156e565b5f5b845181101561081a5761081287878784815181106107eb576107eb612ac6565b602002602001015187858151811061080557610805612ac6565b602002602001015161160f565b6001016107cb565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161086a929190612b1f565b60405180910390a461088081878787878761176d565b505050505050565b606081518351146108b95781518351604051635b05999160e01b815260048101929092526024820152604401610372565b5f83516001600160401b038111156108d3576108d361219c565b6040519080825280602002602001820160405280156108fc578160200160208202803683370190505b5090505f5b845181101561094a576020808202860101516109259060208084028701015161034b565b82828151811061093757610937612ac6565b6020908102919091010152600101610901565b509392505050565b5f61095b6109d2565b6001600160a01b0316634a16607c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610996573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ba9190612b43565b905090565b6109c76118be565b6109d05f6118f0565b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b604080518082019091525f80825260208201526001600160a01b038316610a395760405162461bcd60e51b815260040161037290612730565b505f818152602081815260408083206001600160a01b03861684528252918290208251808401909352546001600160801b038082168452600160801b909104169082015292915050565b5f610a8c6118be565b610aa08484846001600160801b0316611960565b949350505050565b610ab06118be565b5f838152602081815260408083206001600160a01b03881684529091529020546001600160801b031615610b34576040805160018082528183019092525f916020808301908036833701905050905083815f81518110610b1257610b12612ac6565b602002602001018181525050610b328582846001600160801b0316611ae5565b505b5f838152602081815260408083206001600160a01b038816845282529182902080546001600160801b03908116600160801b8683160217909155825180840190935260018352600360fc1b91830191909152610b97918691869190861690611b66565b50505050565b610ba8338383611c2c565b5050565b5f80610bb66109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bf1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c159190612aab565b6001600160801b031690505f5b8351811015610616575f848281518110610c3e57610c3e612ac6565b60200260200101518310610c6b57848281518110610c5e57610c5e612ac6565b6020026020010151610c6d565b825b90505f805f878581518110610c8457610c84612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038b168252909252902054610cce90600160801b90046001600160801b031683612b6e565b9050610d31610d2a5f80898781518110610cea57610cea612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038d16825290925290205483906001600160801b031661149c565b86906114a7565b94505050806001019050610c22565b606082516001600160401b03811115610d5b57610d5b61219c565b604051908082528060200260200182016040528015610d9f57816020015b604080518082019091525f8082526020820152815260200190600190039081610d795790505b5090505f5b8351811015610e0e57610de9848281518110610dc257610dc2612ac6565b6020026020010151848381518110610ddc57610ddc612ac6565b6020026020010151610a00565b828281518110610dfb57610dfb612ac6565b6020908102919091010152600101610da4565b5092915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e595750825b90505f826001600160401b03166001148015610e745750303b155b905081158015610e82575080155b15610ea05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eca57845460ff60401b1916600160401b1785555b610ee160405180602001604052805f815250611cce565b8315610f2757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b5f80610f38611ce8565b6001600160a01b039485165f90815260019190910160209081526040808320959096168252939093525050205460ff1690565b6001600160a01b038416610f915760405162461bcd60e51b815260040161037290612ada565b6001600160a01b038516331480610fad5750610fad8533610f2e565b61100b5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260448201526808185c1c1c9bdd995960ba1b6064820152608401610372565b3361102a81878761101b88611d0c565b61102488611d0c565b8761156e565b6110368686868661160f565b846001600160a01b0316866001600160a01b0316826001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62878760405161108e929190918252602082015260400190565b60405180910390a4610880818787878787611d55565b6110ac6118be565b6001600160a01b0381166110d5575f604051631e4fbdf760e01b81526004016103729190612514565b6110de816118f0565b50565b5f73c1e088fc1323b20bcbee9bd1b9fc9546db5624c56001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611132573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111569190612aab565b6001600160801b0316826001600160801b0316106111ec5773c1e088fc1323b20bcbee9bd1b9fc9546db5624c56001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111be573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111e29190612aab565b6103a69083612b81565b505f919050565b919050565b60605f61120483611e06565b60010190505f816001600160401b038111156112225761122261219c565b6040519080825280601f01601f19166020018201604052801561124c576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461125657509392505050565b60605f61129661271084612bb5565b90505f6112a4606483612bb5565b90505f6112b2606484612bc8565b90505f6112be836111f8565b9050806040516020016112d19190612bdb565b6040516020818303038152906040529050600a82101561130e57806040516020016112fc9190612bff565b60405160208183030381529060405290505b80611318836111f8565b604051602001611329929190612a7d565b60408051601f198184030181529190529695505050505050565b606081515f0361136057505060408051602081019091525f815290565b5f60405180606001604052806040815260200161368f6040913990505f60038451600261138d9190612c23565b6113979190612bb5565b6113a2906004612c36565b6001600160401b038111156113b9576113b961219c565b6040519080825280601f01601f1916602001820160405280156113e3576020820181803683370190505b509050600182016020820185865187015b8082101561144f576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f81168501518453506001830192506113f4565b505060038651066001811461146b576002811461147e57611486565b603d6001830353603d6002830353611486565b603d60018303535b509195945050505050565b5f6106a88284612b6e565b5f6106a88284612c36565b5f6106a88284612c23565b6060604051806101a0016040528061016881526020016138e961016891396114da8484611edd565b604051806102a0016040528061027a8152602001613a5161027a9139611508856001600160801b0316611287565b60405160200161151b9493929190612c4d565b604051602081830303815290604052905092915050565b6060611548826040516020016104879190612e0f565b6040516020016115589190612e2a565b6040516020818303038152906040529050919050565b5f6115776109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190612aab565b6001600160801b031690506001600160a01b038616156115fb576115fb868583611ae5565b611606858583611ae5565b50505050505050565b806001600160a01b038516156116f4575f838152602081815260408083206001600160a01b03891684529091529020546001600160801b0316828110156116ab5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610372565b6116b58282612b81565b5f858152602081815260408083206001600160a01b038b168452909152902080546001600160801b0319166001600160801b0392909216919091179055505b5f838152602081815260408083206001600160a01b0388168452909152902054611727906001600160801b031682611fcd565b5f938452602084815260408086206001600160a01b039790971686529590529390922080546001600160801b0319166001600160801b0390941693909317909255505050565b833b156108805760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906117a89089908990889088908890600401612e6e565b6020604051808303815f875af19250505080156117e2575060408051601f3d908101601f191682019092526117df91810190612ebf565b60015b61188e576117ee612eda565b806308c379a0036118275750611802612ef3565b8061180d5750611829565b8060405162461bcd60e51b81526004016103729190612173565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e20455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610372565b6001600160e01b0319811663bc197c8160e01b146116065760405162461bcd60e51b815260040161037290612f7b565b336118c76109d2565b6001600160a01b0316146109d0573360405163118cdaa760e01b81526004016103729190612514565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f805b8351811015611aa4575f84828151811061197f5761197f612ac6565b602002602001015184106119ac5784828151811061199f5761199f612ac6565b60200260200101516119ae565b835b90505f805f8785815181106119c5576119c5612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038b168252909252902054611a0f90600160801b90046001600160801b031683612b6e565b90508015611a9a57611a38611a315f80898781518110610cea57610cea612ac6565b85906114a7565b9350815f80888681518110611a4f57611a4f612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038c168252909252902080546001600160801b03928316600160801b0292169190911790555b5050600101611963565b507f96f98c54750e4481bfa3aaac1e279e22f034f6bb3fbe5a79cb28d63ac2db367c8382604051611ad6929190612fc3565b60405180910390a19392505050565b5f611af1848484611960565b90508015610b9757611b016109d2565b60405163d47aee5960e01b81526001600160a01b03868116600483015260248201849052919091169063d47aee59906044015f604051808303815f87803b158015611b4a575f80fd5b505af1158015611b5c573d5f803e3d5ffd5b5050505050505050565b6001600160a01b038416611bc65760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610372565b33611bd35f86868661160f565b60408051858152602081018590526001600160a01b03808816925f92918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4610f27815f87878787611d55565b5f611c35611ce8565b90506001600160a01b038316611c5f575f60405162ced3e160e81b81526004016103729190612514565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b611cd733611fd8565b611ce081611fe9565b6110de611ffa565b7f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450090565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110611d4457611d44612ac6565b602090810291909101015292915050565b833b156108805760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611d909089908990889088908890600401612fe4565b6020604051808303815f875af1925050508015611dca575060408051601f3d908101601f19168201909252611dc791810190612ebf565b60015b611dd6576117ee612eda565b6001600160e01b0319811663f23a6e6160e01b146116065760405162461bcd60e51b815260040161037290612f7b565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e445772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611e70576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e8e57662386f26fc10000830492506010015b6305f5e1008310611ea6576305f5e100830492506008015b6127108310611eba57612710830492506004015b60648310611ecc576064830492506002015b600a83106103a65760010192915050565b604051639c45a1d560e01b81526001600160801b03831660048201526060905f9073c1e088fc1323b20bcbee9bd1b9fc9546db5624c590639c45a1d590602401602060405180830381865afa158015611f38573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f5c9190612b43565b90505f60405180610540016040528061051a815260200161317561051a913990508115610aa0575f846001600160801b031611611fa75760405180602001604052805f815250611fc4565b60405180610240016040528061021a81526020016136cf61021a91395b95945050505050565b5f6106a8828461301d565b611fe061200a565b6110de81612053565b611ff161200a565b6110de8161205b565b61200261200a565b6109d061206c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166109d057604051631afcd79f60e31b815260040160405180910390fd5b6110ac61200a565b61206361200a565b6110de8161209a565b61207461200a565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f6120a3611ce8565b9050600281016120b383826130b9565b505050565b80356001600160a01b03811681146111f3575f80fd5b5f80604083850312156120df575f80fd5b6120e8836120b8565b946020939093013593505050565b6001600160e01b0319811681146110de575f80fd5b5f6020828403121561211b575f80fd5b81356106a8816120f6565b5f5b83811015612140578181015183820152602001612128565b50505f910152565b5f815180845261215f816020860160208601612126565b601f01601f19169290920160200192915050565b602081525f6106a86020830184612148565b5f60208284031215612195575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b03811182821017156121d5576121d561219c565b6040525050565b5f6001600160401b038211156121f4576121f461219c565b5060051b60200190565b5f82601f83011261220d575f80fd5b8135602061221a826121dc565b60405161222782826121b0565b80915083815260208101915060208460051b87010193508684111561224a575f80fd5b602086015b84811015612266578035835291830191830161224f565b509695505050505050565b5f8060408385031215612282575f80fd5b61228b836120b8565b915060208301356001600160401b038111156122a5575f80fd5b6122b1858286016121fe565b9150509250929050565b6001600160801b03811681146110de575f80fd5b5f80604083850312156122e0575f80fd5b8235915060208301356122f2816122bb565b809150509250929050565b5f82601f83011261230c575f80fd5b81356001600160401b038111156123255761232561219c565b60405161233c601f8301601f1916602001826121b0565b818152846020838601011115612350575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215612380575f80fd5b612389866120b8565b9450612397602087016120b8565b935060408601356001600160401b03808211156123b2575f80fd5b6123be89838a016121fe565b945060608801359150808211156123d3575f80fd5b6123df89838a016121fe565b935060808801359150808211156123f4575f80fd5b50612401888289016122fd565b9150509295509295909350565b5f806040838503121561241f575f80fd5b82356001600160401b0380821115612435575f80fd5b818501915085601f830112612448575f80fd5b81356020612455826121dc565b60405161246282826121b0565b83815260059390931b8501820192828101915089841115612481575f80fd5b948201945b838610156124a657612497866120b8565b82529482019490820190612486565b965050860135925050808211156124bb575f80fd5b506122b1858286016121fe565b5f815180845260208085019450602084015f5b838110156124f7578151875295820195908201906001016124db565b509495945050505050565b602081525f6106a860208301846124c8565b6001600160a01b0391909116815260200190565b604081016103a6828480516001600160801b03908116835260209182015116910152565b5f805f6060848603121561255e575f80fd5b612567846120b8565b925060208401356001600160401b03811115612581575f80fd5b61258d868287016121fe565b925050604084013561259e816122bb565b809150509250925092565b5f805f80608085870312156125bc575f80fd5b6125c5856120b8565b93506020850135925060408501356125dc816122bb565b915060608501356125ec816122bb565b939692955090935050565b5f8060408385031215612608575f80fd5b612611836120b8565b9150602083013580151581146122f2575f80fd5b602080825282518282018190525f919060409081850190868401855b8281101561267a5761266a84835180516001600160801b03908116835260209182015116910152565b9284019290850190600101612641565b5091979650505050505050565b5f8060408385031215612698575f80fd5b6126a1836120b8565b91506126af602084016120b8565b90509250929050565b5f805f805f60a086880312156126cc575f80fd5b6126d5866120b8565b94506126e3602087016120b8565b9350604086013592506060860135915060808601356001600160401b0381111561270b575f80fd5b612401888289016122fd565b5f60208284031215612727575f80fd5b6106a8826120b8565b6020808252602b908201527f455243313135353a2062616c616e636520717565727920666f7220746865207a60408201526a65726f206164647265737360a81b606082015260800190565b5f815161278c818560208601612126565b9290920192915050565b7603d913730b6b2911d10112332b93a34b634bd32b910169604d1b815284515f906127c8816017850160208a01612126565b7f222c202265787465726e616c5f75726c223a202268747470733a2f2f666572746017918401918201526b2e6265616e2e6d6f6e65792f60a01b6037820152855161281a816043840160208a01612126565b67017343a36b61116160c51b604392909101918201527f226465736372697074696f6e223a2022412074727573747920636f6e73746974604b8201527f75656e74206f6620616e79204661726d65727320746f6f6c626f782c20455243606b8201527f2d31313535204645525420686173206265656e206b6e6f776e20746f20737075608b8201527f72206e65772067726f777468206f6e207365656d696e676c792064656164206660ab8201527f61726d732e204f6e63652070757263686173656420616e64206465706c6f796560cb8201527f6420696e746f2066657274696c652067726f756e64206279204661726d65727360eb8201527f2c2046657274696c697a65722067656e657261746573206e6577205370726f7561010b8201527f74733a20667574757265204265616e732079657420746f20626520726570616961012b8201527f64206279204265616e7374616c6b20696e2065786368616e676520666f72206461014b8201527f6f696e672074686520776f726b206f66205265706c616e74696e67207468652061016b82015275383937ba37b1b7b6171116101134b6b0b3b2911d101160511b61018b820152612a72612a62612a5c6129e76101a185018961277b565b7f222c202261747472696275746573223a205b7b202274726169745f747970652281527f3a20224250462052656d61696e696e67222c22646973706c61795f747970652260208201527f3a2022626f6f73745f6e756d626572222c2276616c7565223a200000000000006040820152605a0190565b8661277b565b63207d5d7d60e01b815260040190565b979650505050505050565b5f8351612a8e818460208801612126565b835190830190612aa2818360208801612126565b01949350505050565b5f60208284031215612abb575f80fd5b81516106a8816122bb565b634e487b7160e01b5f52603260045260245ffd5b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b604081525f612b3160408301856124c8565b8281036020840152611fc481856124c8565b5f60208284031215612b53575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156103a6576103a6612b5a565b6001600160801b03828116828216039080821115610e0e57610e0e612b5a565b634e487b7160e01b5f52601260045260245ffd5b5f82612bc357612bc3612ba1565b500490565b5f82612bd657612bd6612ba1565b500690565b5f8251612bec818460208701612126565b601760f91b920191825250600101919050565b5f8251612c10818460208701612126565b600360fc1b920191825250600101919050565b808201808211156103a6576103a6612b5a565b80820281158282048414176103a6576103a6612b5a565b7f3c7376672077696474683d2232393422206865696768743d223531322220766981527f6577426f783d223020302032393420353132222066696c6c3d226e6f6e65222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201525f8551612d0d81608e850160208a01612126565b855190830190612d2481608e840160208a01612126565b8551910190612d3a81608e840160208901612126565b7f3c7465787420666f6e742d66616d696c793d2273616e732d7365726966222066608e92909101918201527f6f6e742d73697a653d2232302220783d2232302220793d22343930222066696c60ae8201527f6c3d22626c61636b22203e3c747370616e2064793d22302220783d223230223e60ce8201528351612dc48160ee840160208801612126565b612e0360ee828401017f204250462052656d61696e696e67203c2f747370616e3e3c2f746578743e3c2f81526339bb339f60e11b602082015260240190565b98975050505050505050565b5f8251612e20818460208701612126565b9190910192915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081525f8251612e6181601a850160208701612126565b91909101601a0192915050565b6001600160a01b0386811682528516602082015260a0604082018190525f90612e99908301866124c8565b8281036060840152612eab81866124c8565b90508281036080840152612e038185612148565b5f60208284031215612ecf575f80fd5b81516106a8816120f6565b5f60033d1115612ef05760045f803e505f5160e01c5b90565b5f60443d1015612f005790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612f2f57505050505090565b8285019150815181811115612f475750505050505090565b843d8701016020828501011115612f615750505050505090565b612f70602082860101876121b0565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b604081525f612fd560408301856124c8565b90508260208301529392505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f90612a7290830184612148565b6001600160801b03818116838216019080821115610e0e57610e0e612b5a565b600181811c9082168061305157607f821691505b60208210810361306f57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156120b357805f5260205f20601f840160051c8101602085101561309a5750805b601f840160051c820191505b81811015610f27575f81556001016130a6565b81516001600160401b038111156130d2576130d261219c565b6130e6816130e0845461303d565b84613075565b602080601f831160018114613119575f84156131025750858301515b5f19600386901b1c1916600185901b178555610880565b5f85815260208120601f198616915b8281101561314757888601518255948401946001909101908401613128565b508582101561316457878501515f19600388901b60f8161c191681555b5050505050600190811b0190555056fe3c7061746820643d224d37362e363334203136322e393135203231322038342e3133336c34342e3033342037352e3930392d3133352e3834322037382e3534342d34332e3535372d37352e3637315a222066696c6c3d2223383144363732222f3e3c7061746820643d226d3132342e393636203133342e39372034302e3632342d32342e3030312034342e3033312037352e3930362d34312e3039382032332e3736352d34332e3535372d37352e36375a222066696c6c3d2223343642393535222f3e3c7061746820643d226d3231322e3132352034372e3931382d2e3131362033362e3232382d3133352e3339342037382e3736362e3131362d33362e313763302d322e3033322d312e33392d342e3431332d332e31332d352e3435372d2e38372d2e3532332d312e36382d2e3532332d322e3236312d2e3233336c3133352e3339342d37382e373636632e35382d2e33343920312e3333322d2e323920322e3230332e32333320312e3733362e39383920332e31383820332e34323520332e31383820352e345a222066696c6c3d2223364443423630222f3e3c7061746820643d226d3136352e3731332037342e3735322d2e3131362033362e3232382d34302e36352032332e3938382e3131362d33362e313763302d322e3033322d312e33392d342e3431332d332e3132392d352e3435372d2e3837322d2e3532332d312e3638312d2e3532332d322e3236322d2e3233326c34302e36352d32332e393839632e35382d2e33343920312e3333322d2e323920322e3230332e32333320312e3733392e39383620332e31383820332e34323520332e31383820352e345a222066696c6c3d2223343241383443222f3e3c7061746820643d224d37332e353739203132312e32393863312e37333920312e30303520332e31363220332e34323220332e31353920352e3432356c2d2e3130342033362e3139332034332e3535372037352e3636372d39332e3336362d35342e3333392034332e3532312d32352e3031382e3130332d33362e313431632e3030342d3220312e33392d322e37393520332e31332d312e3738375a222066696c6c3d2223324339413243222f3e3c7061746820643d224d3130372e383739203232362e3736362033362e3632203138352e3536356c33352e3734322d32302e3339352031312e3432382031392e3739342032342e3038392034312e3830325a222066696c6c3d2223364443423630222f3e3c7061746820643d226d38312e333438203138302e3733312d34342e37323820342e3833342033352e3734322d32302e33393520382e3938362031352e3536315a222066696c6c3d2223383144363732222f3e20203c7061746820643d224d39352e343933203230392e323337632d392e34343720322e3936362d31372e3834352031302e3633372d32312e36322032312e3535322d2e34393720312e3538392d322e36373820312e3538392d332e32373220302d332e3237322d31302e32332d31312e3430352d31382e3237362d32312e35322d32312e3535322d312e3738342d2e3539382d312e3738342d322e37383220302d332e3337372031302e3131352d332e3331322031382e3137342d31312e3530362032312e35322d32312e3535322e3539342d312e36383920322e3737382d312e36383920332e323732203020332e3736382031302e3638392031312e3536332031382e3139352032312e36322032312e35353220312e3638372e35393520312e36383720322e373739203020332e3337375a222066696c6c3d2223666666222f3e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f3c656c6c697073652063783d223131332e323437222063793d223232302e363838222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d223131332e323437222063793d223232302e363838222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d2237302e303133222063793d223233362e383434222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c7061746820643d226d32362e383235203138342e3234322e3837203232312e3536372039332e3336372035342e3333392d2e3837312d3232312e3536342d39332e3336362d35342e3334325a6d3133362e3433322d37382e3236322e383731203232312e3536382039332e3336372035342e3333382d2e3837312d3232312e3536342d39332e3336372d35342e3334325a222066696c6c3d2223334442353432222f3e3c656c6c697073652063783d223135362e383035222063793d223139382e373135222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d223139382e313033222063793d223138392e363638222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c7061746820643d224d3136342e3437203332372e3234312032382e363235203430352e3736386c2d2e3837382d3232312e353531203133352e3834392d37382e3535392e383734203232312e3538335a222066696c6c3d2223334441413437222f3e3c7061746820643d226d3131382e303539203335342e3037372d34312e3130322032332e3734362d2e3837342d3232312e3535312034312e3130312d32332e3737382e383735203232312e3538335a222066696c6c3d2223334441413437222f3e3c7061746820643d226d32362e383235203138342e3234322e3837203232312e3536372039332e3336372035342e3333392d2e3837312d3232312e3536342d39332e3336362d35342e3334325a6d3133362e3433322d37382e3236322e383731203232312e3536382039332e3336372035342e3333382d2e3837312d3232312e3536342d39332e3336372d35342e3334325a222066696c6c3d2223334442353432222f3e3c7061746820643d226d3235362e383938203338312e3630392d3133352e3834362037382e3532372d2e3837372d3232312e353531203133352e3834392d37382e35362e383734203232312e3538345a222066696c6c3d2223364443423630222f3e3c7061746820643d226d3231302e343836203430382e3434352d34312e3130312032332e3734352d2e3837352d3232312e3535312034312e3130322d32332e3737382e383734203232312e3538345a222066696c6c3d2223334441413437222f3e3c7061746820643d226d3234302e393031203336342e3934392d3130342e3430372036302e3338372d2e3332332d3135372e343737203130342e3430382d36302e3335312e333232203135372e3434315a222066696c6c3d2223666666222f3e3c7061746820643d224d3139352e373839203236382e3032356332332e3133372d362e3731342033362e3837352031302e3633312033322e3330362033352e3233332d342e30322032312e3635322d32312e3335322034322e3834352d33392e3736392034392e3832312d31392e31373120372e32362d33352e3731372d322e3236382d33362e3239372d32332e3936362d2e3636352d32342e3932322031392e3431332d35342e3032312034332e37362d36312e3038385a222066696c6c3d2223343642393535222f3e3c7061746820643d226d3230362e343137203237352e3631352d32382e30382037332e353737732d32342e3536392d33352e3339372032382e30382d37332e3537375a6d2d32332e3032372036382e3336322031392e3536312d35302e3931367332332e3833312031372e3138392d31392e3536312035302e3931365a222066696c6c3d2223666666222f3ea2646970667358221220a2f8e4417afce43d8ecc387daa453d5f5011c6f2ef7c7a22c888196a323a11c164736f6c63430008190033

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610147575f3560e01c80638da5cb5b116100bf578063b6f4208511610079578063b6f42085146102d7578063bf02d309146102ea578063e1c7392a1461030a578063e985e9c514610312578063f242432a14610325578063f2fde38b14610338575f80fd5b80638da5cb5b1461024957806391b7301f1461025e57806395d89b411461027e57806397e6e4671461029e5780639a9a18a2146102b1578063a22cb465146102c4575f80fd5b8063246c0d8711610110578063246c0d87146101e95780632c12865b146101f15780632eb2c2d6146102045780634e1273f41461021957806355234ec014610239578063715018a614610241575f80fd5b8062fdd58e1461014b57806301ffc9a71461017157806306fdde03146101945780630e89341c146101c35780631edb6be1146101d6575b5f80fd5b61015e6101593660046120ce565b61034b565b6040519081526020015b60405180910390f35b61018461017f36600461210b565b6103ac565b6040519015158152602001610168565b60408051808201909152600a8152692332b93a34b634bd32b960b11b60208201525b6040516101689190612173565b6101b66101d1366004612185565b6103fb565b61015e6101e4366004612271565b6104c4565b61015e61061e565b6101b66101ff3660046122cf565b610694565b61021761021236600461236c565b6106af565b005b61022c61022736600461240e565b610888565b6040516101689190612502565b61015e610952565b6102176109bf565b6102516109d2565b6040516101689190612514565b61027161026c3660046120ce565b610a00565b6040516101689190612528565b6040805180820190915260048152631191549560e21b60208201526101b6565b61015e6102ac36600461254c565b610a83565b6102176102bf3660046125a9565b610aa8565b6102176102d23660046125f7565b610b9d565b61015e6102e5366004612271565b610bac565b6102fd6102f836600461240e565b610d40565b6040516101689190612625565b610217610e15565b610184610320366004612687565b610f2e565b6102176103333660046126b8565b610f6b565b610217610346366004612717565b6110a4565b5f6001600160a01b03831661037b5760405162461bcd60e51b815260040161037290612730565b60405180910390fd5b505f818152602081815260408083206001600160a01b03861684529091529020546001600160801b03165b92915050565b5f6001600160e01b03198216636cdb3d1360e11b14806103dc57506001600160e01b031982166303a24d0760e21b145b806103a657506301ffc9a760e01b6001600160e01b03198316146103a6565b60605f610407836110e1565b90505f6104148483610694565b90506040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081525061049b610458866111f8565b610461876111f8565b84610474876001600160801b0316611287565b6040516020016104879493929190612796565b604051602081830303815290604052611343565b6040516020016104ac929190612a7d565b60405160208183030381529060405292505050919050565b5f806104ce6109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610509573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052d9190612aab565b6001600160801b031690505f5b8351811015610616578184828151811061055657610556612ac6565b6020026020010151111561060e5761060b6106045f8087858151811061057e5761057e612ac6565b602002602001015181526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f015f9054906101000a90046001600160801b03166001600160801b03166105fe858886815181106105e8576105e8612ac6565b602002602001015161149190919063ffffffff16565b9061149c565b84906114a7565b92505b60010161053a565b505092915050565b5f6106276109d2565b6001600160a01b031663c85951a16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610662573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106869190612aab565b6001600160801b0316905090565b60606106a86106a384846114b2565b611532565b9392505050565b81518351146107115760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610372565b6001600160a01b0384166107375760405162461bcd60e51b815260040161037290612ada565b6001600160a01b03851633148061075357506107538533610f2e565b6107ba5760405162461bcd60e51b815260206004820152603260248201527f455243313135353a207472616e736665722063616c6c6572206973206e6f74206044820152711bdddb995c881b9bdc88185c1c1c9bdd995960721b6064820152608401610372565b336107c981878787878761156e565b5f5b845181101561081a5761081287878784815181106107eb576107eb612ac6565b602002602001015187858151811061080557610805612ac6565b602002602001015161160f565b6001016107cb565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb878760405161086a929190612b1f565b60405180910390a461088081878787878761176d565b505050505050565b606081518351146108b95781518351604051635b05999160e01b815260048101929092526024820152604401610372565b5f83516001600160401b038111156108d3576108d361219c565b6040519080825280602002602001820160405280156108fc578160200160208202803683370190505b5090505f5b845181101561094a576020808202860101516109259060208084028701015161034b565b82828151811061093757610937612ac6565b6020908102919091010152600101610901565b509392505050565b5f61095b6109d2565b6001600160a01b0316634a16607c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610996573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ba9190612b43565b905090565b6109c76118be565b6109d05f6118f0565b565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b604080518082019091525f80825260208201526001600160a01b038316610a395760405162461bcd60e51b815260040161037290612730565b505f818152602081815260408083206001600160a01b03861684528252918290208251808401909352546001600160801b038082168452600160801b909104169082015292915050565b5f610a8c6118be565b610aa08484846001600160801b0316611960565b949350505050565b610ab06118be565b5f838152602081815260408083206001600160a01b03881684529091529020546001600160801b031615610b34576040805160018082528183019092525f916020808301908036833701905050905083815f81518110610b1257610b12612ac6565b602002602001018181525050610b328582846001600160801b0316611ae5565b505b5f838152602081815260408083206001600160a01b038816845282529182902080546001600160801b03908116600160801b8683160217909155825180840190935260018352600360fc1b91830191909152610b97918691869190861690611b66565b50505050565b610ba8338383611c2c565b5050565b5f80610bb66109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bf1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c159190612aab565b6001600160801b031690505f5b8351811015610616575f848281518110610c3e57610c3e612ac6565b60200260200101518310610c6b57848281518110610c5e57610c5e612ac6565b6020026020010151610c6d565b825b90505f805f878581518110610c8457610c84612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038b168252909252902054610cce90600160801b90046001600160801b031683612b6e565b9050610d31610d2a5f80898781518110610cea57610cea612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038d16825290925290205483906001600160801b031661149c565b86906114a7565b94505050806001019050610c22565b606082516001600160401b03811115610d5b57610d5b61219c565b604051908082528060200260200182016040528015610d9f57816020015b604080518082019091525f8082526020820152815260200190600190039081610d795790505b5090505f5b8351811015610e0e57610de9848281518110610dc257610dc2612ac6565b6020026020010151848381518110610ddc57610ddc612ac6565b6020026020010151610a00565b828281518110610dfb57610dfb612ac6565b6020908102919091010152600101610da4565b5092915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b03165f81158015610e595750825b90505f826001600160401b03166001148015610e745750303b155b905081158015610e82575080155b15610ea05760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610eca57845460ff60401b1916600160401b1785555b610ee160405180602001604052805f815250611cce565b8315610f2757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b5f80610f38611ce8565b6001600160a01b039485165f90815260019190910160209081526040808320959096168252939093525050205460ff1690565b6001600160a01b038416610f915760405162461bcd60e51b815260040161037290612ada565b6001600160a01b038516331480610fad5750610fad8533610f2e565b61100b5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2063616c6c6572206973206e6f74206f776e6572206e6f7260448201526808185c1c1c9bdd995960ba1b6064820152608401610372565b3361102a81878761101b88611d0c565b61102488611d0c565b8761156e565b6110368686868661160f565b846001600160a01b0316866001600160a01b0316826001600160a01b03167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62878760405161108e929190918252602082015260400190565b60405180910390a4610880818787878787611d55565b6110ac6118be565b6001600160a01b0381166110d5575f604051631e4fbdf760e01b81526004016103729190612514565b6110de816118f0565b50565b5f73c1e088fc1323b20bcbee9bd1b9fc9546db5624c56001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611132573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111569190612aab565b6001600160801b0316826001600160801b0316106111ec5773c1e088fc1323b20bcbee9bd1b9fc9546db5624c56001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111be573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111e29190612aab565b6103a69083612b81565b505f919050565b919050565b60605f61120483611e06565b60010190505f816001600160401b038111156112225761122261219c565b6040519080825280601f01601f19166020018201604052801561124c576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461125657509392505050565b60605f61129661271084612bb5565b90505f6112a4606483612bb5565b90505f6112b2606484612bc8565b90505f6112be836111f8565b9050806040516020016112d19190612bdb565b6040516020818303038152906040529050600a82101561130e57806040516020016112fc9190612bff565b60405160208183030381529060405290505b80611318836111f8565b604051602001611329929190612a7d565b60408051601f198184030181529190529695505050505050565b606081515f0361136057505060408051602081019091525f815290565b5f60405180606001604052806040815260200161368f6040913990505f60038451600261138d9190612c23565b6113979190612bb5565b6113a2906004612c36565b6001600160401b038111156113b9576113b961219c565b6040519080825280601f01601f1916602001820160405280156113e3576020820181803683370190505b509050600182016020820185865187015b8082101561144f576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f81168501518453506001830192506113f4565b505060038651066001811461146b576002811461147e57611486565b603d6001830353603d6002830353611486565b603d60018303535b509195945050505050565b5f6106a88284612b6e565b5f6106a88284612c36565b5f6106a88284612c23565b6060604051806101a0016040528061016881526020016138e961016891396114da8484611edd565b604051806102a0016040528061027a8152602001613a5161027a9139611508856001600160801b0316611287565b60405160200161151b9493929190612c4d565b604051602081830303815290604052905092915050565b6060611548826040516020016104879190612e0f565b6040516020016115589190612e2a565b6040516020818303038152906040529050919050565b5f6115776109d2565b6001600160a01b0316639bb4e35a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190612aab565b6001600160801b031690506001600160a01b038616156115fb576115fb868583611ae5565b611606858583611ae5565b50505050505050565b806001600160a01b038516156116f4575f838152602081815260408083206001600160a01b03891684529091529020546001600160801b0316828110156116ab5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610372565b6116b58282612b81565b5f858152602081815260408083206001600160a01b038b168452909152902080546001600160801b0319166001600160801b0392909216919091179055505b5f838152602081815260408083206001600160a01b0388168452909152902054611727906001600160801b031682611fcd565b5f938452602084815260408086206001600160a01b039790971686529590529390922080546001600160801b0319166001600160801b0390941693909317909255505050565b833b156108805760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906117a89089908990889088908890600401612e6e565b6020604051808303815f875af19250505080156117e2575060408051601f3d908101601f191682019092526117df91810190612ebf565b60015b61188e576117ee612eda565b806308c379a0036118275750611802612ef3565b8061180d5750611829565b8060405162461bcd60e51b81526004016103729190612173565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e20455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610372565b6001600160e01b0319811663bc197c8160e01b146116065760405162461bcd60e51b815260040161037290612f7b565b336118c76109d2565b6001600160a01b0316146109d0573360405163118cdaa760e01b81526004016103729190612514565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b5f805b8351811015611aa4575f84828151811061197f5761197f612ac6565b602002602001015184106119ac5784828151811061199f5761199f612ac6565b60200260200101516119ae565b835b90505f805f8785815181106119c5576119c5612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038b168252909252902054611a0f90600160801b90046001600160801b031683612b6e565b90508015611a9a57611a38611a315f80898781518110610cea57610cea612ac6565b85906114a7565b9350815f80888681518110611a4f57611a4f612ac6565b60209081029190910181015182528181019290925260409081015f9081206001600160a01b038c168252909252902080546001600160801b03928316600160801b0292169190911790555b5050600101611963565b507f96f98c54750e4481bfa3aaac1e279e22f034f6bb3fbe5a79cb28d63ac2db367c8382604051611ad6929190612fc3565b60405180910390a19392505050565b5f611af1848484611960565b90508015610b9757611b016109d2565b60405163d47aee5960e01b81526001600160a01b03868116600483015260248201849052919091169063d47aee59906044015f604051808303815f87803b158015611b4a575f80fd5b505af1158015611b5c573d5f803e3d5ffd5b5050505050505050565b6001600160a01b038416611bc65760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610372565b33611bd35f86868661160f565b60408051858152602081018590526001600160a01b03808816925f92918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4610f27815f87878787611d55565b5f611c35611ce8565b90506001600160a01b038316611c5f575f60405162ced3e160e81b81526004016103729190612514565b6001600160a01b038481165f818152600184016020908152604080832094881680845294825291829020805460ff191687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b611cd733611fd8565b611ce081611fe9565b6110de611ffa565b7f88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c450090565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110611d4457611d44612ac6565b602090810291909101015292915050565b833b156108805760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611d909089908990889088908890600401612fe4565b6020604051808303815f875af1925050508015611dca575060408051601f3d908101601f19168201909252611dc791810190612ebf565b60015b611dd6576117ee612eda565b6001600160e01b0319811663f23a6e6160e01b146116065760405162461bcd60e51b815260040161037290612f7b565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e445772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611e70576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e8e57662386f26fc10000830492506010015b6305f5e1008310611ea6576305f5e100830492506008015b6127108310611eba57612710830492506004015b60648310611ecc576064830492506002015b600a83106103a65760010192915050565b604051639c45a1d560e01b81526001600160801b03831660048201526060905f9073c1e088fc1323b20bcbee9bd1b9fc9546db5624c590639c45a1d590602401602060405180830381865afa158015611f38573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f5c9190612b43565b90505f60405180610540016040528061051a815260200161317561051a913990508115610aa0575f846001600160801b031611611fa75760405180602001604052805f815250611fc4565b60405180610240016040528061021a81526020016136cf61021a91395b95945050505050565b5f6106a8828461301d565b611fe061200a565b6110de81612053565b611ff161200a565b6110de8161205b565b61200261200a565b6109d061206c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166109d057604051631afcd79f60e31b815260040160405180910390fd5b6110ac61200a565b61206361200a565b6110de8161209a565b61207461200a565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f6120a3611ce8565b9050600281016120b383826130b9565b505050565b80356001600160a01b03811681146111f3575f80fd5b5f80604083850312156120df575f80fd5b6120e8836120b8565b946020939093013593505050565b6001600160e01b0319811681146110de575f80fd5b5f6020828403121561211b575f80fd5b81356106a8816120f6565b5f5b83811015612140578181015183820152602001612128565b50505f910152565b5f815180845261215f816020860160208601612126565b601f01601f19169290920160200192915050565b602081525f6106a86020830184612148565b5f60208284031215612195575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b03811182821017156121d5576121d561219c565b6040525050565b5f6001600160401b038211156121f4576121f461219c565b5060051b60200190565b5f82601f83011261220d575f80fd5b8135602061221a826121dc565b60405161222782826121b0565b80915083815260208101915060208460051b87010193508684111561224a575f80fd5b602086015b84811015612266578035835291830191830161224f565b509695505050505050565b5f8060408385031215612282575f80fd5b61228b836120b8565b915060208301356001600160401b038111156122a5575f80fd5b6122b1858286016121fe565b9150509250929050565b6001600160801b03811681146110de575f80fd5b5f80604083850312156122e0575f80fd5b8235915060208301356122f2816122bb565b809150509250929050565b5f82601f83011261230c575f80fd5b81356001600160401b038111156123255761232561219c565b60405161233c601f8301601f1916602001826121b0565b818152846020838601011115612350575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215612380575f80fd5b612389866120b8565b9450612397602087016120b8565b935060408601356001600160401b03808211156123b2575f80fd5b6123be89838a016121fe565b945060608801359150808211156123d3575f80fd5b6123df89838a016121fe565b935060808801359150808211156123f4575f80fd5b50612401888289016122fd565b9150509295509295909350565b5f806040838503121561241f575f80fd5b82356001600160401b0380821115612435575f80fd5b818501915085601f830112612448575f80fd5b81356020612455826121dc565b60405161246282826121b0565b83815260059390931b8501820192828101915089841115612481575f80fd5b948201945b838610156124a657612497866120b8565b82529482019490820190612486565b965050860135925050808211156124bb575f80fd5b506122b1858286016121fe565b5f815180845260208085019450602084015f5b838110156124f7578151875295820195908201906001016124db565b509495945050505050565b602081525f6106a860208301846124c8565b6001600160a01b0391909116815260200190565b604081016103a6828480516001600160801b03908116835260209182015116910152565b5f805f6060848603121561255e575f80fd5b612567846120b8565b925060208401356001600160401b03811115612581575f80fd5b61258d868287016121fe565b925050604084013561259e816122bb565b809150509250925092565b5f805f80608085870312156125bc575f80fd5b6125c5856120b8565b93506020850135925060408501356125dc816122bb565b915060608501356125ec816122bb565b939692955090935050565b5f8060408385031215612608575f80fd5b612611836120b8565b9150602083013580151581146122f2575f80fd5b602080825282518282018190525f919060409081850190868401855b8281101561267a5761266a84835180516001600160801b03908116835260209182015116910152565b9284019290850190600101612641565b5091979650505050505050565b5f8060408385031215612698575f80fd5b6126a1836120b8565b91506126af602084016120b8565b90509250929050565b5f805f805f60a086880312156126cc575f80fd5b6126d5866120b8565b94506126e3602087016120b8565b9350604086013592506060860135915060808601356001600160401b0381111561270b575f80fd5b612401888289016122fd565b5f60208284031215612727575f80fd5b6106a8826120b8565b6020808252602b908201527f455243313135353a2062616c616e636520717565727920666f7220746865207a60408201526a65726f206164647265737360a81b606082015260800190565b5f815161278c818560208601612126565b9290920192915050565b7603d913730b6b2911d10112332b93a34b634bd32b910169604d1b815284515f906127c8816017850160208a01612126565b7f222c202265787465726e616c5f75726c223a202268747470733a2f2f666572746017918401918201526b2e6265616e2e6d6f6e65792f60a01b6037820152855161281a816043840160208a01612126565b67017343a36b61116160c51b604392909101918201527f226465736372697074696f6e223a2022412074727573747920636f6e73746974604b8201527f75656e74206f6620616e79204661726d65727320746f6f6c626f782c20455243606b8201527f2d31313535204645525420686173206265656e206b6e6f776e20746f20737075608b8201527f72206e65772067726f777468206f6e207365656d696e676c792064656164206660ab8201527f61726d732e204f6e63652070757263686173656420616e64206465706c6f796560cb8201527f6420696e746f2066657274696c652067726f756e64206279204661726d65727360eb8201527f2c2046657274696c697a65722067656e657261746573206e6577205370726f7561010b8201527f74733a20667574757265204265616e732079657420746f20626520726570616961012b8201527f64206279204265616e7374616c6b20696e2065786368616e676520666f72206461014b8201527f6f696e672074686520776f726b206f66205265706c616e74696e67207468652061016b82015275383937ba37b1b7b6171116101134b6b0b3b2911d101160511b61018b820152612a72612a62612a5c6129e76101a185018961277b565b7f222c202261747472696275746573223a205b7b202274726169745f747970652281527f3a20224250462052656d61696e696e67222c22646973706c61795f747970652260208201527f3a2022626f6f73745f6e756d626572222c2276616c7565223a200000000000006040820152605a0190565b8661277b565b63207d5d7d60e01b815260040190565b979650505050505050565b5f8351612a8e818460208801612126565b835190830190612aa2818360208801612126565b01949350505050565b5f60208284031215612abb575f80fd5b81516106a8816122bb565b634e487b7160e01b5f52603260045260245ffd5b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b604081525f612b3160408301856124c8565b8281036020840152611fc481856124c8565b5f60208284031215612b53575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156103a6576103a6612b5a565b6001600160801b03828116828216039080821115610e0e57610e0e612b5a565b634e487b7160e01b5f52601260045260245ffd5b5f82612bc357612bc3612ba1565b500490565b5f82612bd657612bd6612ba1565b500690565b5f8251612bec818460208701612126565b601760f91b920191825250600101919050565b5f8251612c10818460208701612126565b600360fc1b920191825250600101919050565b808201808211156103a6576103a6612b5a565b80820281158282048414176103a6576103a6612b5a565b7f3c7376672077696474683d2232393422206865696768743d223531322220766981527f6577426f783d223020302032393420353132222066696c6c3d226e6f6e65222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201525f8551612d0d81608e850160208a01612126565b855190830190612d2481608e840160208a01612126565b8551910190612d3a81608e840160208901612126565b7f3c7465787420666f6e742d66616d696c793d2273616e732d7365726966222066608e92909101918201527f6f6e742d73697a653d2232302220783d2232302220793d22343930222066696c60ae8201527f6c3d22626c61636b22203e3c747370616e2064793d22302220783d223230223e60ce8201528351612dc48160ee840160208801612126565b612e0360ee828401017f204250462052656d61696e696e67203c2f747370616e3e3c2f746578743e3c2f81526339bb339f60e11b602082015260240190565b98975050505050505050565b5f8251612e20818460208701612126565b9190910192915050565b7f646174613a696d6167652f7376672b786d6c3b6261736536342c00000000000081525f8251612e6181601a850160208701612126565b91909101601a0192915050565b6001600160a01b0386811682528516602082015260a0604082018190525f90612e99908301866124c8565b8281036060840152612eab81866124c8565b90508281036080840152612e038185612148565b5f60208284031215612ecf575f80fd5b81516106a8816120f6565b5f60033d1115612ef05760045f803e505f5160e01c5b90565b5f60443d1015612f005790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612f2f57505050505090565b8285019150815181811115612f475750505050505090565b843d8701016020828501011115612f615750505050505090565b612f70602082860101876121b0565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b604081525f612fd560408301856124c8565b90508260208301529392505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f90612a7290830184612148565b6001600160801b03818116838216019080821115610e0e57610e0e612b5a565b600181811c9082168061305157607f821691505b60208210810361306f57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156120b357805f5260205f20601f840160051c8101602085101561309a5750805b601f840160051c820191505b81811015610f27575f81556001016130a6565b81516001600160401b038111156130d2576130d261219c565b6130e6816130e0845461303d565b84613075565b602080601f831160018114613119575f84156131025750858301515b5f19600386901b1c1916600185901b178555610880565b5f85815260208120601f198616915b8281101561314757888601518255948401946001909101908401613128565b508582101561316457878501515f19600388901b60f8161c191681555b5050505050600190811b0190555056fe3c7061746820643d224d37362e363334203136322e393135203231322038342e3133336c34342e3033342037352e3930392d3133352e3834322037382e3534342d34332e3535372d37352e3637315a222066696c6c3d2223383144363732222f3e3c7061746820643d226d3132342e393636203133342e39372034302e3632342d32342e3030312034342e3033312037352e3930362d34312e3039382032332e3736352d34332e3535372d37352e36375a222066696c6c3d2223343642393535222f3e3c7061746820643d226d3231322e3132352034372e3931382d2e3131362033362e3232382d3133352e3339342037382e3736362e3131362d33362e313763302d322e3033322d312e33392d342e3431332d332e31332d352e3435372d2e38372d2e3532332d312e36382d2e3532332d322e3236312d2e3233336c3133352e3339342d37382e373636632e35382d2e33343920312e3333322d2e323920322e3230332e32333320312e3733362e39383920332e31383820332e34323520332e31383820352e345a222066696c6c3d2223364443423630222f3e3c7061746820643d226d3136352e3731332037342e3735322d2e3131362033362e3232382d34302e36352032332e3938382e3131362d33362e313763302d322e3033322d312e33392d342e3431332d332e3132392d352e3435372d2e3837322d2e3532332d312e3638312d2e3532332d322e3236322d2e3233326c34302e36352d32332e393839632e35382d2e33343920312e3333322d2e323920322e3230332e32333320312e3733392e39383620332e31383820332e34323520332e31383820352e345a222066696c6c3d2223343241383443222f3e3c7061746820643d224d37332e353739203132312e32393863312e37333920312e30303520332e31363220332e34323220332e31353920352e3432356c2d2e3130342033362e3139332034332e3535372037352e3636372d39332e3336362d35342e3333392034332e3532312d32352e3031382e3130332d33362e313431632e3030342d3220312e33392d322e37393520332e31332d312e3738375a222066696c6c3d2223324339413243222f3e3c7061746820643d224d3130372e383739203232362e3736362033362e3632203138352e3536356c33352e3734322d32302e3339352031312e3432382031392e3739342032342e3038392034312e3830325a222066696c6c3d2223364443423630222f3e3c7061746820643d226d38312e333438203138302e3733312d34342e37323820342e3833342033352e3734322d32302e33393520382e3938362031352e3536315a222066696c6c3d2223383144363732222f3e20203c7061746820643d224d39352e343933203230392e323337632d392e34343720322e3936362d31372e3834352031302e3633372d32312e36322032312e3535322d2e34393720312e3538392d322e36373820312e3538392d332e32373220302d332e3237322d31302e32332d31312e3430352d31382e3237362d32312e35322d32312e3535322d312e3738342d2e3539382d312e3738342d322e37383220302d332e3337372031302e3131352d332e3331322031382e3137342d31312e3530362032312e35322d32312e3535322e3539342d312e36383920322e3737382d312e36383920332e323732203020332e3736382031302e3638392031312e3536332031382e3139352032312e36322032312e35353220312e3638372e35393520312e36383720322e373739203020332e3337375a222066696c6c3d2223666666222f3e4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f3c656c6c697073652063783d223131332e323437222063793d223232302e363838222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d223131332e323437222063793d223232302e363838222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d2237302e303133222063793d223233362e383434222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c7061746820643d226d32362e383235203138342e3234322e3837203232312e3536372039332e3336372035342e3333392d2e3837312d3232312e3536342d39332e3336362d35342e3334325a6d3133362e3433322d37382e3236322e383731203232312e3536382039332e3336372035342e3333382d2e3837312d3232312e3536342d39332e3336372d35342e3334325a222066696c6c3d2223334442353432222f3e3c656c6c697073652063783d223135362e383035222063793d223139382e373135222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c656c6c697073652063783d223139382e313033222063793d223138392e363638222072783d2233382e373137222072793d2233382e373734222066696c6c3d2223374635353333222f3e3c7061746820643d224d3136342e3437203332372e3234312032382e363235203430352e3736386c2d2e3837382d3232312e353531203133352e3834392d37382e3535392e383734203232312e3538335a222066696c6c3d2223334441413437222f3e3c7061746820643d226d3131382e303539203335342e3037372d34312e3130322032332e3734362d2e3837342d3232312e3535312034312e3130312d32332e3737382e383735203232312e3538335a222066696c6c3d2223334441413437222f3e3c7061746820643d226d32362e383235203138342e3234322e3837203232312e3536372039332e3336372035342e3333392d2e3837312d3232312e3536342d39332e3336362d35342e3334325a6d3133362e3433322d37382e3236322e383731203232312e3536382039332e3336372035342e3333382d2e3837312d3232312e3536342d39332e3336372d35342e3334325a222066696c6c3d2223334442353432222f3e3c7061746820643d226d3235362e383938203338312e3630392d3133352e3834362037382e3532372d2e3837372d3232312e353531203133352e3834392d37382e35362e383734203232312e3538345a222066696c6c3d2223364443423630222f3e3c7061746820643d226d3231302e343836203430382e3434352d34312e3130312032332e3734352d2e3837352d3232312e3535312034312e3130322d32332e3737382e383734203232312e3538345a222066696c6c3d2223334441413437222f3e3c7061746820643d226d3234302e393031203336342e3934392d3130342e3430372036302e3338372d2e3332332d3135372e343737203130342e3430382d36302e3335312e333232203135372e3434315a222066696c6c3d2223666666222f3e3c7061746820643d224d3139352e373839203236382e3032356332332e3133372d362e3731342033362e3837352031302e3633312033322e3330362033352e3233332d342e30322032312e3635322d32312e3335322034322e3834352d33392e3736392034392e3832312d31392e31373120372e32362d33352e3731372d322e3236382d33362e3239372d32332e3936362d2e3636352d32342e3932322031392e3431332d35342e3032312034332e37362d36312e3038385a222066696c6c3d2223343642393535222f3e3c7061746820643d226d3230362e343137203237352e3631352d32382e30382037332e353737732d32342e3536392d33352e3339372032382e30382d37332e3537375a6d2d32332e3032372036382e3336322031392e3536312d35302e3931367332332e3833312031372e3138392d31392e3536312035302e3931365a222066696c6c3d2223666666222f3ea2646970667358221220a2f8e4417afce43d8ecc387daa453d5f5011c6f2ef7c7a22c888196a323a11c164736f6c63430008190033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.