ETH Price: $2,744.05 (+5.69%)
Gas: 0.78 Gwei

Contract

0xc178E394e2cD5784e62f2300a8B3EE637339FdBE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StableBPTOracle

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 18 : StableBPTOracle.sol
// SPDX-License-Identifier: MIT
/*
██████╗ ██╗     ██╗   ██╗███████╗██████╗ ███████╗██████╗ ██████╗ ██╗   ██╗
██╔══██╗██║     ██║   ██║██╔════╝██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝
██████╔╝██║     ██║   ██║█████╗  ██████╔╝█████╗  ██████╔╝██████╔╝ ╚████╔╝
██╔══██╗██║     ██║   ██║██╔══╝  ██╔══██╗██╔══╝  ██╔══██╗██╔══██╗  ╚██╔╝
██████╔╝███████╗╚██████╔╝███████╗██████╔╝███████╗██║  ██║██║  ██║   ██║
╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═════╝ ╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝
*/

pragma solidity 0.8.22;

import { FixedPoint } from "../libraries/balancer-v2/FixedPoint.sol";
import { VaultReentrancyLib } from "../libraries/balancer-v2/VaultReentrancyLib.sol";

import "../utils/BlueberryErrors.sol" as Errors;

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

import { IBaseOracle } from "../interfaces/IBaseOracle.sol";
import { IBalancerV2StablePool } from "../interfaces/balancer-v2/IBalancerV2StablePool.sol";
import { IBalancerVault } from "../interfaces/balancer-v2/IBalancerVault.sol";
import { IRateProvider } from "../interfaces/balancer-v2/IRateProvider.sol";

/**
 * @title StableBPTOracle
 * @author BlueberryProtocol
 * @notice Oracle contract which privides price feeds of Stable Balancer LP tokens
 */
contract StableBPTOracle is IBaseOracle, UsingBaseOracle {
    using FixedPoint for uint256;

    /*//////////////////////////////////////////////////////////////////////////
                                      STRUCTS 
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @dev Struct to store token info related to Balancer Pool tokens
     * @param tokens An array of tokens within the pool
     * @param rateProviders An array of rate providers associated with the tokens in the pool
     */
    struct TokenInfo {
        address[] tokens;
        address[] rateProviders;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                      STORAGE 
    //////////////////////////////////////////////////////////////////////////*/

    /// @dev Address of the weighted pool oracle
    IBaseOracle private _weightedPoolOracle;
    /// @dev Address of the Balancer Vault
    IBalancerVault private _vault;
    /// @dev mapping of registered bpt tokens to their token info
    mapping(address => TokenInfo) private _tokenInfo;

    /*//////////////////////////////////////////////////////////////////////////
                                      MODIFIERS
    //////////////////////////////////////////////////////////////////////////*/

    // Protects the oracle from being manipulated via read-only reentrancy
    modifier balancerNonReentrant() {
        VaultReentrancyLib.ensureNotInVaultContext(_vault);
        _;
    }

    /*//////////////////////////////////////////////////////////////////////////
                                     CONSTRUCTOR
    //////////////////////////////////////////////////////////////////////////*/

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /*//////////////////////////////////////////////////////////////////////////
                                      FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /**
     * @notice Initializes the contract
     * @param vault Instance of the Balancer V2 Vault
     * @param base The base oracle instance.
     * @param owner Address of the owner of the contract.
     */
    function initialize(IBalancerVault vault, IBaseOracle base, address owner) external initializer {
        __UsingBaseOracle_init(base, owner);
        _vault = vault;
    }

    /// @inheritdoc IBaseOracle
    function getPrice(address token) public override balancerNonReentrant returns (uint256) {
        TokenInfo memory tokenInfo = getBptInfo(token);
        uint256 tokenLength = tokenInfo.tokens.length;

        if (tokenLength == 0) revert Errors.ORACLE_NOT_SUPPORT_LP(token);

        uint256 minPrice = _getTokensMinPrice(tokenInfo.tokens, tokenInfo.rateProviders, tokenLength);
        uint256 rate = IBalancerV2StablePool(token).getRate();

        return minPrice.mulDown(rate);
    }

    /**
     * @notice Register Balancer Pool token to oracle
     * @dev Stores persistent data of Balancer Pool token
     * @dev An oracle cannot be used for a LP token unless it is registered
     * @param bpt Address of the Balancer Pool token to register
     */
    function registerBpt(address bpt) external onlyOwner {
        if (bpt == address(0)) revert Errors.ZERO_ADDRESS();

        IBalancerV2StablePool pool = IBalancerV2StablePool(bpt);
        (address[] memory tokens, , ) = _vault.getPoolTokens(pool.getPoolId());
        address[] memory rateProviders = pool.getRateProviders();

        uint256 tokenLength = tokens.length;
        // Only ComposableStablePools return BPT within the array of tokens when calling `getPoolTokens`.
        // In order to support all types of stable pools we need to encapsulate `getBPTIndex`
        // in a try/catch block. If the pool is not a ComposableStablePool, we will just
        // set the subTokens to the tokens array that we queried from the vault
        try pool.getBptIndex() returns (uint256 bptIndex) {
            address[] memory subTokens = new address[](tokenLength - 1);
            address[] memory subRateProviders = new address[](tokenLength - 1);

            uint256 index = 0;
            for (uint256 i = 0; i < tokenLength; ++i) {
                if (i != bptIndex) {
                    subTokens[index] = tokens[i];
                    subRateProviders[index] = rateProviders[i];
                    index++;
                }
            }
            _tokenInfo[bpt] = TokenInfo(subTokens, subRateProviders);
        } catch {
            _tokenInfo[bpt] = TokenInfo(tokens, rateProviders);
        }

        emit RegisterLpToken(bpt);
    }

    /**
     * @notice Set the weighted pool oracle
     * @dev Only owner can set the weighted pool oracle
     * @param oracle Address of the oracle to set as the weighted pool oracle
     */
    function setWeightedPoolOracle(address oracle) external onlyOwner {
        if (oracle == address(0)) revert Errors.ZERO_ADDRESS();

        _weightedPoolOracle = IBaseOracle(oracle);
    }

    /**
     * @notice Fetches the TokenInfo struct of a given LP token
     * @param bpt Balancer Pool Token address
     * @return TokenInfo struct of given LP token
     */
    function getBptInfo(address bpt) public view returns (TokenInfo memory) {
        return _tokenInfo[bpt];
    }

    /// @notice Returns the weighted pool oracle address
    function getWeightedPoolOracle() external view returns (address) {
        return address(_weightedPoolOracle);
    }

    /**
     * @notice Returns the minimum price of a given array of tokens
     * @param tokens An array of tokens within the pool
     * @param rateProviders An array of rate providers associated with the tokens in the pool
     * @param length The length of the array of tokens
     * @return The minimum price of the given array of tokens
     */
    function _getTokensMinPrice(
        address[] memory tokens,
        address[] memory rateProviders,
        uint256 length
    ) internal returns (uint256) {
        uint256 minPrice;
        address minToken;

        for (uint256 i = 0; i < length; ++i) {
            address minCandidate = tokens[i];
            IRateProvider rateProvider = IRateProvider(rateProviders[i]);
            uint256 minCandidatePrice = _calculateMinCandidatePrice(rateProvider, minCandidate);

            if (minCandidatePrice < minPrice || i == 0) {
                minToken = minCandidate;
                minPrice = minCandidatePrice;
            }
        }

        return minPrice;
    }

    /**
     * @notice Returns the price of a given token
     * @param rateProvider The rate provider associated with the token
     * @param minCandidate The token to calculate the minimum price for
     * @return The price of the given token
     */
    function _calculateMinCandidatePrice(IRateProvider rateProvider, address minCandidate) internal returns (uint256) {
        uint256 minCandidatePrice = _getMarketPrice(minCandidate);

        if (address(rateProvider) != address(0)) {
            uint256 rateProviderPrice = rateProvider.getRate();
            minCandidatePrice = minCandidatePrice.divDown(rateProviderPrice);
        }

        return minCandidatePrice;
    }

    /**
     * @notice Returns the price of a given token
     * @dev If the token is not supported by the base oracle, we assume that it is a nested pool
     *    and we will try to get the price from the weighted pool oracle or recursively
     * @param token Address of the token to fetch the price for.
     * @return The Market price of the given token
     */
    function _getMarketPrice(address token) internal returns (uint256) {
        try _base.getPrice(token) returns (uint256 price) {
            return price;
        } catch {
            try _weightedPoolOracle.getPrice(token) returns (uint256 price) {
                return price;
            } catch {
                return getPrice(token);
            }
        }
    }
}

File 2 of 18 : FixedPoint.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

import "./BalancerErrors.sol";

import "./LogExpMath.sol";

/* solhint-disable private-vars-leading-underscore */

/// forked from https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/math/FixedPoint.sol
/// Updated to solidity version 0.8.X
library FixedPoint {
    uint256 internal constant ONE = 1e18; // 18 decimal places
    uint256 internal constant TWO = 2 * ONE;
    uint256 internal constant FOUR = 4 * ONE;
    uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14)

    // Minimum base for the power function when the exponent is 'free' (larger than ONE).
    uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18;

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition

        uint256 c = a + b;
        _require(c >= a, BalancerErrors.ADD_OVERFLOW);
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        // Fixed Point addition is the same as regular checked addition

        _require(b <= a, BalancerErrors.SUB_OVERFLOW);
        uint256 c = a - b;
        return c;
    }

    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 product = a * b;
        _require(a == 0 || product / a == b, BalancerErrors.MUL_OVERFLOW);

        return product / ONE;
    }

    function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 product = a * b;
        _require(a == 0 || product / a == b, BalancerErrors.MUL_OVERFLOW);

        if (product == 0) {
            return 0;
        } else {
            // The traditional divUp formula is:
            // divUp(x, y) := (x + y - 1) / y
            // To avoid intermediate overflow in the addition, we distribute the division and get:
            // divUp(x, y) := (x - 1) / y + 1
            // Note that this requires x != 0, which we already tested for.

            return ((product - 1) / ONE) + 1;
        }
    }

    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        _require(b != 0, BalancerErrors.ZERO_DIVISION);

        if (a == 0) {
            return 0;
        } else {
            uint256 aInflated = a * ONE;
            _require(aInflated / a == ONE, BalancerErrors.DIV_INTERNAL); // mul overflow

            return aInflated / b;
        }
    }

    function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
        _require(b != 0, BalancerErrors.ZERO_DIVISION);

        if (a == 0) {
            return 0;
        } else {
            uint256 aInflated = a * ONE;
            _require(aInflated / a == ONE, BalancerErrors.DIV_INTERNAL); // mul overflow

            // The traditional divUp formula is:
            // divUp(x, y) := (x + y - 1) / y
            // To avoid intermediate overflow in the addition, we distribute the division and get:
            // divUp(x, y) := (x - 1) / y + 1
            // Note that this requires x != 0, which we already tested for.

            return ((aInflated - 1) / b) + 1;
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above
     * the true value (that is, the error function expected - actual is always positive).
     */
    function powDown(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50
        // and 80/20 Weighted Pools
        if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulDown(x, x);
        } else if (y == FOUR) {
            uint256 square = mulDown(x, x);
            return mulDown(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            if (raw < maxError) {
                return 0;
            } else {
                return sub(raw, maxError);
            }
        }
    }

    /**
     * @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below
     * the true value (that is, the error function expected - actual is always negative).
     */
    function powUp(uint256 x, uint256 y) internal pure returns (uint256) {
        // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50
        // and 80/20 Weighted Pools
        if (y == ONE) {
            return x;
        } else if (y == TWO) {
            return mulUp(x, x);
        } else if (y == FOUR) {
            uint256 square = mulUp(x, x);
            return mulUp(square, square);
        } else {
            uint256 raw = LogExpMath.pow(x, y);
            uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);

            return add(raw, maxError);
        }
    }

    /**
     * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1.
     *
     * Useful when computing the complement for values with some level of relative error, as it strips this error and
     * prevents intermediate negative values.
     */
    function complement(uint256 x) internal pure returns (uint256) {
        return (x < ONE) ? (ONE - x) : 0;
    }
}

File 3 of 18 : VaultReentrancyLib.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// From https://github.com/balancer/balancer-v2-monorepo/blob/fc3e5735a07438ab506931f56adf64dede1441b1/pkg/pool-utils/contracts/lib/VaultReentrancyLib.sol

pragma solidity >=0.7.1 <0.9.0;

import "./BalancerErrors.sol";
import "../../interfaces/balancer-v2/IBalancerVault.sol";

library VaultReentrancyLib {
    /**
     * @dev Ensure we are not in a Vault context when this function is called, by attempting a no-op internal
     * balance operation. If we are already in a Vault transaction (e.g., a swap, join, or exit), the Vault's
     * reentrancy protection will cause this function to revert.
     *
     * The exact function call doesn't really matter: we're just trying to trigger the Vault reentrancy check
     * (and not hurt anything in case it works). An empty operation array with no specific operation at all works
     * for that purpose, and is also the least expensive in terms of gas and bytecode size.
     *
     * Call this at the top of any function that can cause a state change in a pool and is either public itself,
     * or called by a public function *outside* a Vault operation (e.g., join, exit, or swap).
     *
     * If this is *not* called in functions that are vulnerable to the read-only reentrancy issue described
     * here (https://forum.balancer.fi/t/reentrancy-vulnerability-scope-expanded/4345), those functions are unsafe,
     * and subject to manipulation that may result in loss of funds.
     */
    function ensureNotInVaultContext(IBalancerVault vault) internal view {
        // Perform the following operation to trigger the Vault's reentrancy guard:
        //
        // IVault.UserBalanceOp[] memory noop = new IVault.UserBalanceOp[](0);
        // _vault.manageUserBalance(noop);
        //
        // However, use a static call so that it can be a view function (even though the function is non-view).
        // This allows the library to be used more widely, as some functions that need to be protected might be
        // view.
        //
        // This staticcall always reverts, but we need to make sure it doesn't fail due to a re-entrancy attack.
        // Staticcalls consume all gas forwarded to them on a revert caused by storage modification.
        // By default, almost the entire available gas is forwarded to the staticcall,
        // causing the entire call to revert with an 'out of gas' error.
        //
        // We set the gas limit to 10k for the staticcall to
        // avoid wasting gas when it reverts due to storage modification.
        // `manageUserBalance` is a non-reentrant function in the Vault, so calling it invokes `_enterNonReentrant`
        // in the `ReentrancyGuard` contract, reproduced here:
        //
        //    function _enterNonReentrant() private {
        //        // If the Vault is actually being reentered, it will revert in the first line, at the `_require` that
        //        // checks the reentrancy flag, with "BAL#400" (corresponding to BalancerErrors.REENTRANCY) in the revertData.
        //        // The full revertData will be: `abi.encodeWithSignature("Error(string)", "BAL#400")`.
        //        _require(_status != _ENTERED, BalancerErrors.REENTRANCY);
        //
        //        // If the Vault is not being reentered, the check above will pass: but it will *still* revert,
        //        // because the next line attempts to modify storage during a staticcall. However, this type of
        //        // failure results in empty revertData.
        //        _status = _ENTERED;
        //    }
        //
        // So based on this analysis, there are only two possible revertData values: empty, or abi.encoded BAL#400.
        //
        // It is of course much more bytecode and gas efficient to check for zero-length revertData than to compare it
        // to the encoded REENTRANCY revertData.
        //
        // While it should be impossible for the call to fail in any other way (especially since it reverts before
        // `manageUserBalance` even gets called), any other error would generate non-zero revertData, so checking for
        // empty data guards against this case too.

        (, bytes memory revertData) = address(vault).staticcall{ gas: 10_000 }(
            abi.encodeWithSelector(vault.manageUserBalance.selector, 0)
        );

        _require(revertData.length == 0, BalancerErrors.REENTRANCY);
    }
}

File 4 of 18 : BlueberryErrors.sol
// SPDX-License-Identifier: MIT
/*
██████╗ ██╗     ██╗   ██╗███████╗██████╗ ███████╗██████╗ ██████╗ ██╗   ██╗
██╔══██╗██║     ██║   ██║██╔════╝██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝
██████╔╝██║     ██║   ██║█████╗  ██████╔╝█████╗  ██████╔╝██████╔╝ ╚████╔╝
██╔══██╗██║     ██║   ██║██╔══╝  ██╔══██╗██╔══╝  ██╔══██╗██╔══██╗  ╚██╔╝
██████╔╝███████╗╚██████╔╝███████╗██████╔╝███████╗██║  ██║██║  ██║   ██║
╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═════╝ ╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝
*/
/**
 * @title BlueberryErrors
 * @author BlueberryProtocol
 * @notice containing all errors used in Blueberry protocol
 */
/// title BlueberryErrors
/// @notice containing all errors used in Blueberry protocol
pragma solidity 0.8.22;

/*//////////////////////////////////////////////////////////////////////////
                                COMMON ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when an action involves zero amount of tokens.
error ZERO_AMOUNT();

/// @notice Thrown when the address provided is the zero address.
error ZERO_ADDRESS();

/// @notice Thrown when the lengths of input arrays do not match.
error INPUT_ARRAY_MISMATCH();

/// @notice Thrown when the caller is not authorized to call the function.
error UNAUTHORIZED();

/*//////////////////////////////////////////////////////////////////////////
                                ORACLE ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when the delay time exceeds allowed limits.
error TOO_LONG_DELAY(uint256 delayTime);

/// @notice Thrown when there's no maximum delay set for a token.
error NO_MAX_DELAY(address token);

/// @notice Thrown when the price information for a token is outdated.
error PRICE_OUTDATED(address token);

/// @notice Thrown when the price obtained is negative.
error PRICE_NEGATIVE(address token);

/// @notice Thrown when the sequencer is offline
error SEQUENCER_DOWN(address sequencer);

/// @notice Thrown when the grace period for a sequencer is not over yet.
error SEQUENCER_GRACE_PERIOD_NOT_OVER(address sequencer);

/// @notice Thrown when the price deviation exceeds allowed limits.
error OUT_OF_DEVIATION_CAP(uint256 deviation);

/// @notice Thrown when the number of sources exceeds the allowed length.
error EXCEED_SOURCE_LEN(uint256 length);

/// @notice Thrown when no primary source is available for the token.
error NO_PRIMARY_SOURCE(address token);

/// @notice Thrown when no valid price source is available for the token.
error NO_VALID_SOURCE(address token);

/// @notice Thrown when the deviation value exceeds the threshold.
error EXCEED_DEVIATION();

/// @notice Thrown when the mean price is below the acceptable threshold.
error TOO_LOW_MEAN(uint256 mean);

/// @notice Thrown when no mean price is set for the token.
error NO_MEAN(address token);

/// @notice Thrown when no stable pool exists for the token.
error NO_STABLEPOOL(address token);

/// @notice Thrown when the price fetch process fails for a token.
error PRICE_FAILED(address token);

/// @notice Thrown when the liquidation threshold is set too high.
error LIQ_THRESHOLD_TOO_HIGH(uint256 threshold);

/// @notice Thrown when the liquidation threshold is set too low.
error LIQ_THRESHOLD_TOO_LOW(uint256 threshold);

/// @notice Thrown when the oracle doesn't support a specific token.
error ORACLE_NOT_SUPPORT(address token);

/// @notice Thrown when the oracle doesn't support a specific LP pair token.
error ORACLE_NOT_SUPPORT_LP(address lp);

/// @notice Thrown when the oracle doesn't support a specific wToken.
error ORACLE_NOT_SUPPORT_WTOKEN(address wToken);

/// @notice Thrown when there is no route to fetch data for the oracle
error NO_ORACLE_ROUTE(address token);

/// @notice Thrown when a value is out of an acceptable range.
error VALUE_OUT_OF_RANGE();

/// @notice Thrown when specified limits are incorrect.
error INCORRECT_LIMITS();

/// @notice Thrown when Curve LP is already registered.
error CRV_LP_ALREADY_REGISTERED(address lp);

/*//////////////////////////////////////////////////////////////////////////
                            GENERAL SPELL ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when the caller isn't recognized as a bank.
error NOT_BANK(address caller);

/// @notice Thrown when the collateral doesn't exist for a strategy.
error COLLATERAL_NOT_EXIST(uint256 strategyId, address colToken);

/// @notice Thrown when the strategy ID doesn't correspond to an existing strategy.
error STRATEGY_NOT_EXIST(address spell, uint256 strategyId);

/// @notice Thrown when the position size exceeds maximum limits.
error EXCEED_MAX_POS_SIZE(uint256 strategyId);

/// @notice Thrown when the position size is below minimum requirements.
error EXCEED_MIN_POS_SIZE(uint256 strategyId);

/// @notice Thrown when the loan-to-value ratio exceeds allowed maximum.
error EXCEED_MAX_LTV();

/// @notice Thrown when the strategy ID provided is incorrect.
error INCORRECT_STRATEGY_ID(uint256 strategyId);

/// @notice Thrown when the position size is invalid.
error INVALID_POS_SIZE();

/// @notice Thrown when an incorrect liquidity pool token is provided.
error INCORRECT_LP(address lpToken);

/// @notice Thrown when an incorrect pool ID is provided.
error INCORRECT_PID(uint256 pid);

/// @notice Thrown when an incorrect collateral token is provided.
error INCORRECT_COLTOKEN(address colToken);

/// @notice Thrown when an incorrect underlying token is provided.
error INCORRECT_UNDERLYING(address uToken);

/// @notice Thrown when an incorrect debt token is provided.
error INCORRECT_DEBT(address debtToken);

/// @notice Thrown when a swap fails.
error SWAP_FAILED(address swapToken);

/*//////////////////////////////////////////////////////////////////////////
                                VAULT ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when borrowing from the vault fails.
error BORROW_FAILED(uint256 amount);

/// @notice Thrown when repaying to the vault fails.
error REPAY_FAILED(uint256 amount);

/// @notice Thrown when lending to the vault fails.
error LEND_FAILED(uint256 amount);

/// @notice Thrown when redeeming from the vault fails.
error REDEEM_FAILED(uint256 amount);

/*//////////////////////////////////////////////////////////////////////////
                                WRAPPER ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when a duplicate tokenId is added.
error DUPLICATE_TOKEN_ID(uint256 tokenId);

/// @notice Thrown when an invalid token ID is provided.
error INVALID_TOKEN_ID(uint256 tokenId);

/// @notice Thrown when an incorrect pool ID is provided.
error BAD_PID(uint256 pid);

/// @notice Thrown when a mismatch in reward per share is detected.
error BAD_REWARD_PER_SHARE(uint256 rewardPerShare);

/*//////////////////////////////////////////////////////////////////////////
                                BANK ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when a function is called without a required execution flag.
error NOT_UNDER_EXECUTION();

/// @notice Thrown when a transaction isn't initiated by the expected spell.
error NOT_FROM_SPELL(address from);

/// @notice Thrown when the sender is not the owner of a given position ID.
error NOT_FROM_OWNER(uint256 positionId, address sender);

/// @notice Thrown when a spell address isn't whitelisted.
error SPELL_NOT_WHITELISTED(address spell);

/// @notice Thrown when a token isn't whitelisted.
error TOKEN_NOT_WHITELISTED(address token);

/// @notice Thrown when a bank isn't listed for a given token.
error BANK_NOT_LISTED(address token);

/// @notice Thrown when a bank doesn't exist for an index.
error BANK_NOT_EXIST(uint8 index);

/// @notice Thrown when a bank is already listed for a given token.
error BANK_ALREADY_LISTED();

/// @notice Thrown when the bank limit is reached.
error BANK_LIMIT();

/// @notice Thrown when the BTOKEN is already added.
error BTOKEN_ALREADY_ADDED();

/// @notice Thrown when the lending action isn't allowed.
error LEND_NOT_ALLOWED();

/// @notice Thrown when the borrowing action isn't allowed.
error BORROW_NOT_ALLOWED();

/// @notice Thrown when the repaying action isn't allowed.
error REPAY_NOT_ALLOWED();

/// @notice Thrown when the redeeming action isn't allowed.
error WITHDRAW_LEND_NOT_ALLOWED();

/// @notice Thrown when certain actions are locked.
error LOCKED();

/// @notice Thrown when an action isn't executed.
error NOT_IN_EXEC();

/// @notice Thrown when the repayment allowance hasn't been warmed up.
error REPAY_ALLOW_NOT_WARMED_UP();

/// @notice Thrown when a different collateral type exists.
error DIFF_COL_EXIST(address collToken);

/// @notice Thrown when a position is not eligible for liquidation.
error NOT_LIQUIDATABLE(uint256 positionId);

/// @notice Thrown when a position is flagged as bad or invalid.
error BAD_POSITION(uint256 posId);

/// @notice Thrown when collateral for a specific position is flagged as bad or invalid.
error BAD_COLLATERAL(uint256 positionId);

/// @notice Thrown when there's insufficient collateral for an operation.
error INSUFFICIENT_COLLATERAL();

/// @notice Thrown when an attempted repayment exceeds the actual debt.
error REPAY_EXCEEDS_DEBT(uint256 repay, uint256 debt);

/// @notice Thrown when an invalid utility token is provided.
error INVALID_UTOKEN(address uToken);

/// @notice Thrown when a borrow operation results in zero shares.
error BORROW_ZERO_SHARE(uint256 borrowAmount);

/*//////////////////////////////////////////////////////////////////////////
                            CONFIGURATION ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when a certain ratio is too high for an operation.
error RATIO_TOO_HIGH(uint256 ratio);

/// @notice Thrown when an invalid fee distribution is detected.
error INVALID_FEE_DISTRIBUTION();

/// @notice Thrown when no treasury is set for fee distribution.
error NO_TREASURY_SET();

/// @notice Thrown when a fee window has already started.
error FEE_WINDOW_ALREADY_STARTED();

/// @notice Thrown when a fee window duration is too long.
error FEE_WINDOW_TOO_LONG(uint256 windowTime);

/*//////////////////////////////////////////////////////////////////////////
                                UTILITY ERRORS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Thrown when an operation has surpassed its deadline.
error EXPIRED(uint256 deadline);

File 5 of 18 : UsingBaseOracle.sol
// SPDX-License-Identifier: MIT
/*
██████╗ ██╗     ██╗   ██╗███████╗██████╗ ███████╗██████╗ ██████╗ ██╗   ██╗
██╔══██╗██║     ██║   ██║██╔════╝██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝
██████╔╝██║     ██║   ██║█████╗  ██████╔╝█████╗  ██████╔╝██████╔╝ ╚████╔╝
██╔══██╗██║     ██║   ██║██╔══╝  ██╔══██╗██╔══╝  ██╔══██╗██╔══██╗  ╚██╔╝
██████╔╝███████╗╚██████╔╝███████╗██████╔╝███████╗██║  ██║██║  ██║   ██║
╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═════╝ ╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝
*/

pragma solidity 0.8.22;

import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";

import { IBaseOracle } from "../interfaces/IBaseOracle.sol";

/**
 * @title UsingBaseOracle
 * @author BlueberryProtocol
 * @dev This contract serves as a base for other contracts that need access
 *      to an external oracle service. It provides an immutable reference to a
 *      specified oracle source.
 */
abstract contract UsingBaseOracle is Ownable2StepUpgradeable {
    /// @dev Base oracle source
    IBaseOracle internal _base;

    /*//////////////////////////////////////////////////////////////////////////
                                     CONSTRUCTOR
    //////////////////////////////////////////////////////////////////////////*/
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /*//////////////////////////////////////////////////////////////////////////
                                       FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/

    /* solhint-disable func-name-mixedcase */
    /**
     * @dev Initializes the Base oracle source.
     * @param base Address of the Base oracle source.
     * @param owner Address of the owner.
     */
    function __UsingBaseOracle_init(IBaseOracle base, address owner) internal onlyInitializing {
        _base = base;
        __Ownable2Step_init();
        _transferOwnership(owner);
    }

    /* solhint-enable func-name-mixedcase */

    /// @notice Returns the address of the Base oracle source.
    function getBaseOracle() public view returns (IBaseOracle) {
        return _base;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     *      variables without shifting down storage in the inheritance chain.
     *      See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[10] private __gap;
}

File 6 of 18 : IBaseOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

/**
 * @title IBaseOracle
 * @author BlueberryProtocol
 * @notice Interface for a basic oracle that provides price data for assets.
 */
interface IBaseOracle {
    /**
     * @notice Event emitted when a new LP token is registered within its respective implementation.
     * @param token Address of the LP token being registered
     */
    event RegisterLpToken(address token);

    /**
     * @notice Fetches the price of the given token in USD with 18 decimals precision.
     * @param token Address of the ERC-20 token for which the price is requested.
     * @return The USD price of the given token, multiplied by 10**18.
     */
    function getPrice(address token) external returns (uint256);
}

File 7 of 18 : IBalancerV2StablePool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

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

interface IBalancerV2StablePool is IBalancerV2Pool {
    function getRate() external view returns (uint256);

    function getBptIndex() external view returns (uint256);

    function getRateProviders() external view returns (address[] memory);
}

File 8 of 18 : IBalancerVault.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

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

interface IBalancerVault {
    enum UserBalanceOpKind {
        DEPOSIT_INTERNAL,
        WITHDRAW_INTERNAL,
        TRANSFER_INTERNAL,
        TRANSFER_EXTERNAL
    }

    /**
     * @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received
     without manual WETH wrapping or unwrapping.
     */
    struct UserBalanceOp {
        UserBalanceOpKind kind;
        IAsset asset;
        uint256 amount;
        address sender;
        address payable recipient;
    }

    struct JoinPoolRequest {
        address[] assets;
        uint256[] maxAmountsIn;
        bytes userData;
        bool fromInternalBalance;
    }

    struct ExitPoolRequest {
        address[] assets;
        uint256[] minAmountsOut;
        bytes userData;
        bool toInternalBalance;
    }

    function joinPool(
        bytes32 poolId,
        address sender,
        address recipient,
        JoinPoolRequest memory request
    ) external payable;

    function exitPool(bytes32 poolId, address sender, address recipient, ExitPoolRequest memory request) external;

    function getPoolTokens(
        bytes32 poolId
    ) external view returns (address[] memory tokens, uint256[] memory balances, uint256 lastChangedBlock);

    function getPool(bytes32 pid) external view returns (address pool, uint256 poolType);

    function manageUserBalance(UserBalanceOp[] memory ops) external;
}

File 9 of 18 : IRateProvider.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

interface IRateProvider {
    function getRate() external view returns (uint256);
}

File 10 of 18 : BalancerErrors.sol
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

/// Forked from https://github.com/balancer-labs/balancer-v2-monorepo/blob/3703c43c89dc693b918d20ebb0d9e4b205d31c2c/contracts/lib/helpers/BalancerErrors.sol
/// Updated solidity version to 0.8.X

// solhint-disable

/**
 * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
 * supported.
 * Uses the default 'BAL' prefix for the error code
 */
function _require(bool condition, uint256 errorCode) pure {
    if (!condition) _revert(errorCode);
}

/**
 * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
 * supported.
 */
function _require(bool condition, uint256 errorCode, bytes3 prefix) pure {
    if (!condition) _revert(errorCode, prefix);
}

/**
 * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
 * Uses the default 'BAL' prefix for the error code
 */
function _revert(uint256 errorCode) pure {
    _revert(errorCode, 0x42414c); // This is the raw byte representation of "BAL"
}

/**
 * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
 */
function _revert(uint256 errorCode, bytes3 prefix) pure {
    uint256 prefixUint = uint256(uint24(prefix));
    // We're going to dynamically create a revert string based on the error code, with the following format:
    // 'BAL#{errorCode}'
    // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
    //
    // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
    // number (8 to 16 bits) than the individual string characters.
    //
    // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
    // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
    // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
    assembly {
        // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
        // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
        // the '0' character.

        let units := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let tenths := add(mod(errorCode, 10), 0x30)

        errorCode := div(errorCode, 10)
        let hundreds := add(mod(errorCode, 10), 0x30)

        // With the individual characters, we can now construct the full string.
        // We first append the '#' character (0x23) to the prefix. In the case of 'BAL', it results in 0x42414c23 ('BAL#')
        // Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the
        // characters to it, each shifted by a multiple of 8.
        // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
        // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
        // array).
        let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint)))

        let revertReason := shl(200, add(formattedPrefix, add(add(units, shl(8, tenths)), shl(16, hundreds))))

        // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
        // message will have the following layout:
        // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]

        // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
        // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
        mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
        // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
        mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
        // The string length is fixed: 7 characters.
        mstore(0x24, 7)
        // Finally, the string itself is stored.
        mstore(0x44, revertReason)

        // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
        // the encoded message is therefore 4 + 32 + 32 + 32 = 100.
        revert(0, 100)
    }
}

library BalancerErrors {
    // Math
    uint256 internal constant ADD_OVERFLOW = 0;
    uint256 internal constant SUB_OVERFLOW = 1;
    uint256 internal constant SUB_UNDERFLOW = 2;
    uint256 internal constant MUL_OVERFLOW = 3;
    uint256 internal constant ZERO_DIVISION = 4;
    uint256 internal constant DIV_INTERNAL = 5;
    uint256 internal constant X_OUT_OF_BOUNDS = 6;
    uint256 internal constant Y_OUT_OF_BOUNDS = 7;
    uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
    uint256 internal constant INVALID_EXPONENT = 9;

    // Input
    uint256 internal constant OUT_OF_BOUNDS = 100;
    uint256 internal constant UNSORTED_ARRAY = 101;
    uint256 internal constant UNSORTED_TOKENS = 102;
    uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
    uint256 internal constant ZERO_TOKEN = 104;

    // Shared pools
    uint256 internal constant MIN_TOKENS = 200;
    uint256 internal constant MAX_TOKENS = 201;
    uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
    uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
    uint256 internal constant MINIMUM_BPT = 204;
    uint256 internal constant CALLER_NOT_VAULT = 205;
    uint256 internal constant UNINITIALIZED = 206;
    uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
    uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
    uint256 internal constant EXPIRED_PERMIT = 209;
    uint256 internal constant NOT_TWO_TOKENS = 210;
    uint256 internal constant DISABLED = 211;

    // Pools
    uint256 internal constant MIN_AMP = 300;
    uint256 internal constant MAX_AMP = 301;
    uint256 internal constant MIN_WEIGHT = 302;
    uint256 internal constant MAX_STABLE_TOKENS = 303;
    uint256 internal constant MAX_IN_RATIO = 304;
    uint256 internal constant MAX_OUT_RATIO = 305;
    uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
    uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
    uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
    uint256 internal constant INVALID_TOKEN = 309;
    uint256 internal constant UNHANDLED_JOIN_KIND = 310;
    uint256 internal constant ZERO_INVARIANT = 311;
    uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
    uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
    uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
    uint256 internal constant ORACLE_INVALID_INDEX = 315;
    uint256 internal constant ORACLE_BAD_SECS = 316;
    uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;
    uint256 internal constant AMP_ONGOING_UPDATE = 318;
    uint256 internal constant AMP_RATE_TOO_HIGH = 319;
    uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;
    uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;
    uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;
    uint256 internal constant RELAYER_NOT_CONTRACT = 323;
    uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;
    uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;
    uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;
    uint256 internal constant SWAPS_DISABLED = 327;
    uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;
    uint256 internal constant PRICE_RATE_OVERFLOW = 329;
    uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;
    uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;
    uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;
    uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;
    uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;
    uint256 internal constant OUT_OF_TARGET_RANGE = 335;
    uint256 internal constant UNHANDLED_EXIT_KIND = 336;
    uint256 internal constant UNAUTHORIZED_EXIT = 337;
    uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;
    uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;
    uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;
    uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;
    uint256 internal constant INVALID_INITIALIZATION = 342;
    uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;
    uint256 internal constant FEATURE_DISABLED = 344;
    uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;
    uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346;
    uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347;
    uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348;
    uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349;
    uint256 internal constant MAX_WEIGHT = 350;
    uint256 internal constant UNAUTHORIZED_JOIN = 351;
    uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352;
    uint256 internal constant FRACTIONAL_TARGET = 353;

    // Lib
    uint256 internal constant REENTRANCY = 400;
    uint256 internal constant SENDER_NOT_ALLOWED = 401;
    uint256 internal constant PAUSED = 402;
    uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
    uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
    uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
    uint256 internal constant INSUFFICIENT_BALANCE = 406;
    uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
    uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
    uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
    uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
    uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
    uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
    uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
    uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
    uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
    uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
    uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
    uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
    uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
    uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
    uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
    uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
    uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
    uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;
    uint256 internal constant CALLER_IS_NOT_OWNER = 426;
    uint256 internal constant NEW_OWNER_IS_ZERO = 427;
    uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;
    uint256 internal constant CALL_TO_NON_CONTRACT = 429;
    uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;
    uint256 internal constant NOT_PAUSED = 431;
    uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;
    uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;
    uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;
    uint256 internal constant INVALID_OPERATION = 435;
    uint256 internal constant CODEC_OVERFLOW = 436;
    uint256 internal constant IN_RECOVERY_MODE = 437;
    uint256 internal constant NOT_IN_RECOVERY_MODE = 438;
    uint256 internal constant INDUCED_FAILURE = 439;
    uint256 internal constant EXPIRED_SIGNATURE = 440;
    uint256 internal constant MALFORMED_SIGNATURE = 441;
    uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442;
    uint256 internal constant UNHANDLED_FEE_TYPE = 443;

    // Vault
    uint256 internal constant INVALID_POOL_ID = 500;
    uint256 internal constant CALLER_NOT_POOL = 501;
    uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
    uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
    uint256 internal constant INVALID_SIGNATURE = 504;
    uint256 internal constant EXIT_BELOW_MIN = 505;
    uint256 internal constant JOIN_ABOVE_MAX = 506;
    uint256 internal constant SWAP_LIMIT = 507;
    uint256 internal constant SWAP_DEADLINE = 508;
    uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
    uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
    uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
    uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
    uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
    uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
    uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
    uint256 internal constant INSUFFICIENT_ETH = 516;
    uint256 internal constant UNALLOCATED_ETH = 517;
    uint256 internal constant ETH_TRANSFER = 518;
    uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
    uint256 internal constant TOKENS_MISMATCH = 520;
    uint256 internal constant TOKEN_NOT_REGISTERED = 521;
    uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
    uint256 internal constant TOKENS_ALREADY_SET = 523;
    uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
    uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
    uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
    uint256 internal constant POOL_NO_TOKENS = 527;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;

    // Fees
    uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
    uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
    uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
    uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603;

    // Misc
    uint256 internal constant UNIMPLEMENTED = 998;
    uint256 internal constant SHOULD_NOT_HAPPEN = 999;
}

File 11 of 18 : LogExpMath.sol
// SPDX-License-Identifier: MIT
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.

// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pragma solidity ^0.8.0;

import "./BalancerErrors.sol";

/* solhint-disable */

/// Forked from https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/math/LogExpMath.sol
/// updated to solidity version 0.8.x
/**
 * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
 *
 * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
 * exponentiation and logarithm (where the base is Euler's number).
 *
 * @author Fernando Martinelli - @fernandomartinelli
 * @author Sergio Yuhjtman - @sergioyuhjtman
 * @author Daniel Fernandez - @dmf7z
 */
library LogExpMath {
    // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
    // two numbers, and multiply by ONE when dividing them.

    // All arguments and return values are 18 decimal fixed point numbers.
    int256 constant ONE_18 = 1e18;

    // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
    // case of ln36, 36 decimals.
    int256 constant ONE_20 = 1e20;
    int256 constant ONE_36 = 1e36;

    // The domain of natural exponentiation is bound by the word size and number of decimals used.
    //
    // Because internally the result will be stored using 20 decimals, the largest possible result is
    // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
    // The smallest possible result is 10^(-18), which makes largest negative argument
    // ln(10^(-18)) = -41.446531673892822312.
    // We use 130.0 and -41.0 to have some safety margin.
    int256 constant MAX_NATURAL_EXPONENT = 130e18;
    int256 constant MIN_NATURAL_EXPONENT = -41e18;

    // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
    // 256 bit integer.
    int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
    int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;

    uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);

    // 18 decimal constants
    int256 constant x0 = 128000000000000000000; // 2ˆ7
    int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
    int256 constant x1 = 64000000000000000000; // 2ˆ6
    int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)

    // 20 decimal constants
    int256 constant x2 = 3200000000000000000000; // 2ˆ5
    int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
    int256 constant x3 = 1600000000000000000000; // 2ˆ4
    int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
    int256 constant x4 = 800000000000000000000; // 2ˆ3
    int256 constant a4 = 298095798704172827474000; // eˆ(x4)
    int256 constant x5 = 400000000000000000000; // 2ˆ2
    int256 constant a5 = 5459815003314423907810; // eˆ(x5)
    int256 constant x6 = 200000000000000000000; // 2ˆ1
    int256 constant a6 = 738905609893065022723; // eˆ(x6)
    int256 constant x7 = 100000000000000000000; // 2ˆ0
    int256 constant a7 = 271828182845904523536; // eˆ(x7)
    int256 constant x8 = 50000000000000000000; // 2ˆ-1
    int256 constant a8 = 164872127070012814685; // eˆ(x8)
    int256 constant x9 = 25000000000000000000; // 2ˆ-2
    int256 constant a9 = 128402541668774148407; // eˆ(x9)
    int256 constant x10 = 12500000000000000000; // 2ˆ-3
    int256 constant a10 = 113314845306682631683; // eˆ(x10)
    int256 constant x11 = 6250000000000000000; // 2ˆ-4
    int256 constant a11 = 106449445891785942956; // eˆ(x11)

    /**
     * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
     *
     * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function pow(uint256 x, uint256 y) internal pure returns (uint256) {
        if (y == 0) {
            // We solve the 0^0 indetermination by making it equal one.
            return uint256(ONE_18);
        }

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

        // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
        // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
        // x^y = exp(y * ln(x)).

        // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
        _require(x >> 255 == 0, BalancerErrors.X_OUT_OF_BOUNDS);
        int256 x_int256 = int256(x);

        // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
        // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.

        // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
        _require(y < MILD_EXPONENT_BOUND, BalancerErrors.Y_OUT_OF_BOUNDS);
        int256 y_int256 = int256(y);

        int256 logx_times_y;
        if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
            int256 ln_36_x = _ln_36(x_int256);

            // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
            // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
            // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
            // (downscaled) last 18 decimals.
            logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
        } else {
            logx_times_y = _ln(x_int256) * y_int256;
        }
        logx_times_y /= ONE_18;

        // Finally, we compute exp(y * ln(x)) to arrive at x^y
        _require(
            MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
            BalancerErrors.PRODUCT_OUT_OF_BOUNDS
        );

        return uint256(exp(logx_times_y));
    }

    /**
     * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
     *
     * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
     */
    function exp(int256 x) internal pure returns (int256) {
        _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, BalancerErrors.INVALID_EXPONENT);

        if (x < 0) {
            // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
            // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
            // Fixed point division requires multiplying by ONE_18.
            return ((ONE_18 * ONE_18) / exp(-x));
        }

        // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
        // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
        // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
        // decomposition.
        // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
        // decomposition, which will be lower than the smallest x_n.
        // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
        // We mutate x by subtracting x_n, making it the remainder of the decomposition.

        // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
        // intermediate overflows. Instead we store them as plain integers, with 0 decimals.
        // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
        // decomposition.

        // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
        // it and compute the accumulated product.

        int256 firstAN;
        if (x >= x0) {
            x -= x0;
            firstAN = a0;
        } else if (x >= x1) {
            x -= x1;
            firstAN = a1;
        } else {
            firstAN = 1; // One with no decimal places
        }

        // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
        // smaller terms.
        x *= 100;

        // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
        // one. Recall that fixed point multiplication requires dividing by ONE_20.
        int256 product = ONE_20;

        if (x >= x2) {
            x -= x2;
            product = (product * a2) / ONE_20;
        }
        if (x >= x3) {
            x -= x3;
            product = (product * a3) / ONE_20;
        }
        if (x >= x4) {
            x -= x4;
            product = (product * a4) / ONE_20;
        }
        if (x >= x5) {
            x -= x5;
            product = (product * a5) / ONE_20;
        }
        if (x >= x6) {
            x -= x6;
            product = (product * a6) / ONE_20;
        }
        if (x >= x7) {
            x -= x7;
            product = (product * a7) / ONE_20;
        }
        if (x >= x8) {
            x -= x8;
            product = (product * a8) / ONE_20;
        }
        if (x >= x9) {
            x -= x9;
            product = (product * a9) / ONE_20;
        }

        // x10 and x11 are unnecessary here since we have high enough precision already.

        // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
        // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).

        int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
        int256 term; // Each term in the sum, where the nth term is (x^n / n!).

        // The first term is simply x.
        term = x;
        seriesSum += term;

        // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
        // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.

        term = ((term * x) / ONE_20) / 2;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 3;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 4;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 5;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 6;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 7;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 8;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 9;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 10;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 11;
        seriesSum += term;

        term = ((term * x) / ONE_20) / 12;
        seriesSum += term;

        // 12 Taylor terms are sufficient for 18 decimal precision.

        // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
        // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
        // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
        // and then drop two digits to return an 18 decimal value.

        return (((product * seriesSum) / ONE_20) * firstAN) / 100;
    }

    /**
     * @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.
     */
    function log(int256 arg, int256 base) internal pure returns (int256) {
        // This performs a simple base change: log(arg, base) = ln(arg) / ln(base).

        // Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by
        // upscaling.

        int256 logBase;
        if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {
            logBase = _ln_36(base);
        } else {
            logBase = _ln(base) * ONE_18;
        }

        int256 logArg;
        if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {
            logArg = _ln_36(arg);
        } else {
            logArg = _ln(arg) * ONE_18;
        }

        // When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places
        return (logArg * ONE_18) / logBase;
    }

    /**
     * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function ln(int256 a) internal pure returns (int256) {
        // The real natural logarithm is not defined for negative numbers or zero.
        _require(a > 0, BalancerErrors.OUT_OF_BOUNDS);
        if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
            return _ln_36(a) / ONE_18;
        } else {
            return _ln(a);
        }
    }

    /**
     * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
     */
    function _ln(int256 a) private pure returns (int256) {
        if (a < ONE_18) {
            // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
            // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
            // Fixed point division requires multiplying by ONE_18.
            return (-_ln((ONE_18 * ONE_18) / a));
        }

        // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
        // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
        // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
        // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
        // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
        // decomposition, which will be lower than the smallest a_n.
        // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
        // We mutate a by subtracting a_n, making it the remainder of the decomposition.

        // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
        // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
        // ONE_18 to convert them to fixed point.
        // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
        // by it and compute the accumulated sum.

        int256 sum = 0;
        if (a >= a0 * ONE_18) {
            a /= a0; // Integer, not fixed point division
            sum += x0;
        }

        if (a >= a1 * ONE_18) {
            a /= a1; // Integer, not fixed point division
            sum += x1;
        }

        // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
        sum *= 100;
        a *= 100;

        // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.

        if (a >= a2) {
            a = (a * ONE_20) / a2;
            sum += x2;
        }

        if (a >= a3) {
            a = (a * ONE_20) / a3;
            sum += x3;
        }

        if (a >= a4) {
            a = (a * ONE_20) / a4;
            sum += x4;
        }

        if (a >= a5) {
            a = (a * ONE_20) / a5;
            sum += x5;
        }

        if (a >= a6) {
            a = (a * ONE_20) / a6;
            sum += x6;
        }

        if (a >= a7) {
            a = (a * ONE_20) / a7;
            sum += x7;
        }

        if (a >= a8) {
            a = (a * ONE_20) / a8;
            sum += x8;
        }

        if (a >= a9) {
            a = (a * ONE_20) / a9;
            sum += x9;
        }

        if (a >= a10) {
            a = (a * ONE_20) / a10;
            sum += x10;
        }

        if (a >= a11) {
            a = (a * ONE_20) / a11;
            sum += x11;
        }

        // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
        // that converges rapidly for values of `a` close to one - the same one used in ln_36.
        // Let z = (a - 1) / (a + 1).
        // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
        // division by ONE_20.
        int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
        int256 z_squared = (z * z) / ONE_20;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_20;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_20;
        seriesSum += num / 11;

        // 6 Taylor terms are sufficient for 36 decimal precision.

        // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
        seriesSum *= 2;

        // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
        // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
        // value.

        return (sum + seriesSum) / 100;
    }

    /**
     * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
     * for x close to one.
     *
     * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
     */
    function _ln_36(int256 x) private pure returns (int256) {
        // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
        // worthwhile.

        // First, we transform x to a 36 digit fixed point value.
        x *= ONE_18;

        // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
        // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))

        // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
        // division by ONE_36.
        int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
        int256 z_squared = (z * z) / ONE_36;

        // num is the numerator of the series: the z^(2 * n + 1) term
        int256 num = z;

        // seriesSum holds the accumulated sum of each term in the series, starting with the initial z
        int256 seriesSum = num;

        // In each step, the numerator is multiplied by z^2
        num = (num * z_squared) / ONE_36;
        seriesSum += num / 3;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 5;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 7;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 9;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 11;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 13;

        num = (num * z_squared) / ONE_36;
        seriesSum += num / 15;

        // 8 Taylor terms are sufficient for 36 decimal precision.

        // All that remains is multiplying by 2 (non fixed point).
        return seriesSum * 2;
    }
}

File 12 of 18 : Ownable2StepUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    address private _pendingOwner;

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

    function __Ownable2Step_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 13 of 18 : IBalancerV2Pool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

interface IBalancerV2Pool {
    function getVault() external view returns (address);

    function getPoolId() external view returns (bytes32);

    function totalSupply() external view returns (uint256);

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

File 14 of 18 : IAsset.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.22;

interface IAsset {
    // solhint-disable-previous-line no-empty-blocks
}

File 15 of 18 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../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.
 *
 * By default, the owner account will be the one that deploys the contract. 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 {
    address private _owner;

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

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

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 16 of 18 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @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 Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 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 functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _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 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _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() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @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 {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

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

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

File 17 of 18 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;
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;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 18 of 18 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

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

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

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
        }
    }
}

Settings
{
  "remappings": [
    "@blueberry/=lib/blueberry-core/contracts/",
    "@blueberry-stakevest/=lib/blueberry-stakevest/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/blueberry-core/node_modules/@openzeppelin/contracts-upgradeable/",
    "src/=src/BlueberryContracts/",
    "openzeppelin-contracts-upgradeable/contracts/=lib/blueberry-stakevest/lib/openzeppelin-contracts-upgradeable/contracts/",
    "solady/=lib/blueberry-stakevest/lib/solady/",
    "@chainlink/=lib/blueberry-core/node_modules/@chainlink/",
    "@eth-optimism/=lib/blueberry-core/node_modules/@eth-optimism/contracts/",
    "@uniswap/=lib/blueberry-core/node_modules/@uniswap/",
    "base64-sol/=lib/blueberry-core/node_modules/base64-sol/",
    "blueberry-core/=lib/blueberry-core/contracts/",
    "blueberry-stakevest/=lib/blueberry-stakevest/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "eth-gas-reporter/=lib/blueberry-core/node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat-deploy/=lib/blueberry-core/node_modules/hardhat-deploy/",
    "hardhat/=lib/blueberry-core/node_modules/hardhat/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "openzeppelin/=lib/blueberry-stakevest/lib/openzeppelin-contracts-upgradeable/contracts/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "v3-core/=lib/blueberry-stakevest/lib/v3-core/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"lp","type":"address"}],"name":"ORACLE_NOT_SUPPORT_LP","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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":false,"internalType":"address","name":"token","type":"address"}],"name":"RegisterLpToken","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getBaseOracle","outputs":[{"internalType":"contract IBaseOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bpt","type":"address"}],"name":"getBptInfo","outputs":[{"components":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"rateProviders","type":"address[]"}],"internalType":"struct StableBPTOracle.TokenInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getWeightedPoolOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBalancerVault","name":"vault","type":"address"},{"internalType":"contract IBaseOracle","name":"base","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bpt","type":"address"}],"name":"registerBpt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"setWeightedPoolOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50610019610026565b610021610026565b6100e5565b600054610100900460ff16156100925760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100e3576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611461806100f46000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c806379ba50971161007157806379ba5097146101455780638da5cb5b1461014d57806396a421041461015e578063c0c53b8b1461017e578063e30c397814610191578063f2fde38b146101a257600080fd5b8063257cc90d146100b95780633088794e146100ce5780633158952b146100f857806341976e091461010b578063590ed5a71461012c578063715018a61461013d575b600080fd5b6100cc6100c736600461103c565b6101b5565b005b6097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b6100cc61010636600461103c565b6105f6565b61011e61011936600461103c565b610647565b6040519081526020016100ef565b60a2546001600160a01b03166100db565b6100cc610733565b6100cc610747565b6033546001600160a01b03166100db565b61017161016c36600461103c565b6107c1565b6040516100ef919061109e565b6100cc61018c3660046110e0565b6108b4565b6065546001600160a01b03166100db565b6100cc6101b036600461103c565b6109e5565b6101bd610a56565b6001600160a01b0381166101e45760405163538ba4f960e01b815260040160405180910390fd5b60a3546040805163038fff2d60e41b8152905183926000926001600160a01b039182169263f94d4668928616916338fff2d09160048083019260209291908290030181865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f919061112b565b6040518263ffffffff1660e01b815260040161027d91815260200190565b600060405180830381865afa15801561029a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c29190810190611227565b505090506000826001600160a01b031663238a2d596040518163ffffffff1660e01b8152600401600060405180830381865afa158015610306573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261032e91908101906112eb565b9050600082519050836001600160a01b03166382687a566040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610390575060408051601f3d908101601f1916820190925261038d9181019061112b565b60015b6103f65760408051808201825284815260208082018590526001600160a01b038816600090815260a482529290922081518051929391926103d49284920190610fad565b5060208281015180516103ed9260018501920190610fad565b509050506105b3565b6000610403600184611336565b67ffffffffffffffff81111561041b5761041b611144565b604051908082528060200260200182016040528015610444578160200160208202803683370190505b5090506000610454600185611336565b67ffffffffffffffff81111561046c5761046c611144565b604051908082528060200260200182016040528015610495578160200160208202803683370190505b5090506000805b8581101561055157848114610549578781815181106104bd576104bd611349565b60200260200101518483815181106104d7576104d7611349565b60200260200101906001600160a01b031690816001600160a01b03168152505086818151811061050957610509611349565b602002602001015183838151811061052357610523611349565b6001600160a01b0390921660209283029190910190910152816105458161135f565b9250505b60010161049c565b5060408051808201825284815260208082018590526001600160a01b038c16600090815260a482529290922081518051929391926105929284920190610fad565b5060208281015180516105ab9260018501920190610fad565b505050505050505b6040516001600160a01b03861681527f40b39da51b8530ffd459fd9b3a53974555c0744c0f8b0f15499c129933acbd909060200160405180910390a15050505050565b6105fe610a56565b6001600160a01b0381166106255760405163538ba4f960e01b815260040160405180910390fd5b60a280546001600160a01b0319166001600160a01b0392909216919091179055565b60a35460009061065f906001600160a01b0316610ab0565b600061066a836107c1565b80515190915060008190036106a25760405163385fd8c560e11b81526001600160a01b03851660048201526024015b60405180910390fd5b60006106b78360000151846020015184610b5d565b90506000856001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071d919061112b565b90506107298282610be6565b9695505050505050565b61073b610a56565b6107456000610c30565b565b60655433906001600160a01b031681146107b55760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610699565b6107be81610c30565b50565b604080518082018252606080825260208083018290526001600160a01b038516600090815260a482528490208451815492830281018401865294850182815293949390928492849184018282801561084257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610824575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156108a457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610886575b5050505050815250509050919050565b600054610100900460ff16158080156108d45750600054600160ff909116105b806108ee5750303b1580156108ee575060005460ff166001145b6109515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610699565b6000805460ff191660011790558015610974576000805461ff0019166101001790555b61097e8383610c49565b60a380546001600160a01b0319166001600160a01b03861617905580156109df576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b6109ed610a56565b606580546001600160a01b0383166001600160a01b03199091168117909155610a1e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6033546001600160a01b031633146107455760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610699565b604080516000602480830182905283518084039091018152604490920183526020820180516001600160e01b03166303a38fa160e21b17905291516001600160a01b0384169161271091610b049190611378565b6000604051808303818686fa925050503d8060008114610b40576040519150601f19603f3d011682016040523d82523d6000602084013e610b45565b606091505b50915050610b598151600014610190610c9c565b5050565b60008080805b84811015610bdb576000878281518110610b7f57610b7f611349565b602002602001015190506000878381518110610b9d57610b9d611349565b602002602001015190506000610bb38284610caa565b905085811080610bc1575083155b15610bcd578294508095505b505050806001019050610b63565b509095945050505050565b600080610bf383856113a7565b9050610c14841580610c0d575083610c0b86846113be565b145b6003610c9c565b610c26670de0b6b3a7640000826113be565b9150505b92915050565b606580546001600160a01b03191690556107be81610d42565b600054610100900460ff16610c705760405162461bcd60e51b8152600401610699906113e0565b609780546001600160a01b0319166001600160a01b038416179055610c93610d94565b610b5981610c30565b81610b5957610b5981610dc3565b600080610cb683610dd3565b90506001600160a01b03841615610d3b576000846001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2b919061112b565b9050610d378282610eb5565b9150505b9392505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16610dbb5760405162461bcd60e51b8152600401610699906113e0565b610745610f1a565b6107be816210905360ea1b610f4a565b6097546040516341976e0960e01b81526001600160a01b03838116600483015260009216906341976e09906024016020604051808303816000875af1925050508015610e3c575060408051601f3d908101601f19168201909252610e399181019061112b565b60015b610c2a5760a2546040516341976e0960e01b81526001600160a01b038481166004830152909116906341976e09906024016020604051808303816000875af1925050508015610ea8575060408051601f3d908101601f19168201909252610ea59181019061112b565b60015b610c2a57610c2a82610647565b6000610ec48215156004610c9c565b82600003610ed457506000610c2a565b6000610ee8670de0b6b3a7640000856113a7565b9050610f08670de0b6b3a7640000610f0086846113be565b146005610c9c565b610f1283826113be565b915050610c2a565b600054610100900460ff16610f415760405162461bcd60e51b8152600401610699906113e0565b61074533610c30565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b828054828255906000526020600020908101928215611002579160200282015b8281111561100257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610fcd565b5061100e929150611012565b5090565b5b8082111561100e5760008155600101611013565b6001600160a01b03811681146107be57600080fd5b60006020828403121561104e57600080fd5b8135610d3b81611027565b60008151808452602080850194506020840160005b838110156110935781516001600160a01b03168752958201959082019060010161106e565b509495945050505050565b6020815260008251604060208401526110ba6060840182611059565b90506020840151601f198483030160408501526110d78282611059565b95945050505050565b6000806000606084860312156110f557600080fd5b833561110081611027565b9250602084013561111081611027565b9150604084013561112081611027565b809150509250925092565b60006020828403121561113d57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561118357611183611144565b604052919050565b600067ffffffffffffffff8211156111a5576111a5611144565b5060051b60200190565b600082601f8301126111c057600080fd5b815160206111d56111d08361118b565b61115a565b8083825260208201915060208460051b8701019350868411156111f757600080fd5b602086015b8481101561121c57805161120f81611027565b83529183019183016111fc565b509695505050505050565b60008060006060848603121561123c57600080fd5b835167ffffffffffffffff8082111561125457600080fd5b611260878388016111af565b945060209150818601518181111561127757600080fd5b86019050601f8101871361128a57600080fd5b80516112986111d08261118b565b81815260059190911b820183019083810190898311156112b757600080fd5b928401925b828410156112d5578351825292840192908401906112bc565b8096505050505050604084015190509250925092565b6000602082840312156112fd57600080fd5b815167ffffffffffffffff81111561131457600080fd5b610c26848285016111af565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c2a57610c2a611320565b634e487b7160e01b600052603260045260246000fd5b60006001820161137157611371611320565b5060010190565b6000825160005b81811015611399576020818601810151858301520161137f565b506000920191825250919050565b8082028115828204841417610c2a57610c2a611320565b6000826113db57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220129abf25519126b9563c2706db767de067ebd1faabcb5e8d1dc46242de0f30b664736f6c63430008160033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100b45760003560e01c806379ba50971161007157806379ba5097146101455780638da5cb5b1461014d57806396a421041461015e578063c0c53b8b1461017e578063e30c397814610191578063f2fde38b146101a257600080fd5b8063257cc90d146100b95780633088794e146100ce5780633158952b146100f857806341976e091461010b578063590ed5a71461012c578063715018a61461013d575b600080fd5b6100cc6100c736600461103c565b6101b5565b005b6097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b6100cc61010636600461103c565b6105f6565b61011e61011936600461103c565b610647565b6040519081526020016100ef565b60a2546001600160a01b03166100db565b6100cc610733565b6100cc610747565b6033546001600160a01b03166100db565b61017161016c36600461103c565b6107c1565b6040516100ef919061109e565b6100cc61018c3660046110e0565b6108b4565b6065546001600160a01b03166100db565b6100cc6101b036600461103c565b6109e5565b6101bd610a56565b6001600160a01b0381166101e45760405163538ba4f960e01b815260040160405180910390fd5b60a3546040805163038fff2d60e41b8152905183926000926001600160a01b039182169263f94d4668928616916338fff2d09160048083019260209291908290030181865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f919061112b565b6040518263ffffffff1660e01b815260040161027d91815260200190565b600060405180830381865afa15801561029a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c29190810190611227565b505090506000826001600160a01b031663238a2d596040518163ffffffff1660e01b8152600401600060405180830381865afa158015610306573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261032e91908101906112eb565b9050600082519050836001600160a01b03166382687a566040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610390575060408051601f3d908101601f1916820190925261038d9181019061112b565b60015b6103f65760408051808201825284815260208082018590526001600160a01b038816600090815260a482529290922081518051929391926103d49284920190610fad565b5060208281015180516103ed9260018501920190610fad565b509050506105b3565b6000610403600184611336565b67ffffffffffffffff81111561041b5761041b611144565b604051908082528060200260200182016040528015610444578160200160208202803683370190505b5090506000610454600185611336565b67ffffffffffffffff81111561046c5761046c611144565b604051908082528060200260200182016040528015610495578160200160208202803683370190505b5090506000805b8581101561055157848114610549578781815181106104bd576104bd611349565b60200260200101518483815181106104d7576104d7611349565b60200260200101906001600160a01b031690816001600160a01b03168152505086818151811061050957610509611349565b602002602001015183838151811061052357610523611349565b6001600160a01b0390921660209283029190910190910152816105458161135f565b9250505b60010161049c565b5060408051808201825284815260208082018590526001600160a01b038c16600090815260a482529290922081518051929391926105929284920190610fad565b5060208281015180516105ab9260018501920190610fad565b505050505050505b6040516001600160a01b03861681527f40b39da51b8530ffd459fd9b3a53974555c0744c0f8b0f15499c129933acbd909060200160405180910390a15050505050565b6105fe610a56565b6001600160a01b0381166106255760405163538ba4f960e01b815260040160405180910390fd5b60a280546001600160a01b0319166001600160a01b0392909216919091179055565b60a35460009061065f906001600160a01b0316610ab0565b600061066a836107c1565b80515190915060008190036106a25760405163385fd8c560e11b81526001600160a01b03851660048201526024015b60405180910390fd5b60006106b78360000151846020015184610b5d565b90506000856001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071d919061112b565b90506107298282610be6565b9695505050505050565b61073b610a56565b6107456000610c30565b565b60655433906001600160a01b031681146107b55760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610699565b6107be81610c30565b50565b604080518082018252606080825260208083018290526001600160a01b038516600090815260a482528490208451815492830281018401865294850182815293949390928492849184018282801561084257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610824575b50505050508152602001600182018054806020026020016040519081016040528092919081815260200182805480156108a457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610886575b5050505050815250509050919050565b600054610100900460ff16158080156108d45750600054600160ff909116105b806108ee5750303b1580156108ee575060005460ff166001145b6109515760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610699565b6000805460ff191660011790558015610974576000805461ff0019166101001790555b61097e8383610c49565b60a380546001600160a01b0319166001600160a01b03861617905580156109df576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b6109ed610a56565b606580546001600160a01b0383166001600160a01b03199091168117909155610a1e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6033546001600160a01b031633146107455760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610699565b604080516000602480830182905283518084039091018152604490920183526020820180516001600160e01b03166303a38fa160e21b17905291516001600160a01b0384169161271091610b049190611378565b6000604051808303818686fa925050503d8060008114610b40576040519150601f19603f3d011682016040523d82523d6000602084013e610b45565b606091505b50915050610b598151600014610190610c9c565b5050565b60008080805b84811015610bdb576000878281518110610b7f57610b7f611349565b602002602001015190506000878381518110610b9d57610b9d611349565b602002602001015190506000610bb38284610caa565b905085811080610bc1575083155b15610bcd578294508095505b505050806001019050610b63565b509095945050505050565b600080610bf383856113a7565b9050610c14841580610c0d575083610c0b86846113be565b145b6003610c9c565b610c26670de0b6b3a7640000826113be565b9150505b92915050565b606580546001600160a01b03191690556107be81610d42565b600054610100900460ff16610c705760405162461bcd60e51b8152600401610699906113e0565b609780546001600160a01b0319166001600160a01b038416179055610c93610d94565b610b5981610c30565b81610b5957610b5981610dc3565b600080610cb683610dd3565b90506001600160a01b03841615610d3b576000846001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2b919061112b565b9050610d378282610eb5565b9150505b9392505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16610dbb5760405162461bcd60e51b8152600401610699906113e0565b610745610f1a565b6107be816210905360ea1b610f4a565b6097546040516341976e0960e01b81526001600160a01b03838116600483015260009216906341976e09906024016020604051808303816000875af1925050508015610e3c575060408051601f3d908101601f19168201909252610e399181019061112b565b60015b610c2a5760a2546040516341976e0960e01b81526001600160a01b038481166004830152909116906341976e09906024016020604051808303816000875af1925050508015610ea8575060408051601f3d908101601f19168201909252610ea59181019061112b565b60015b610c2a57610c2a82610647565b6000610ec48215156004610c9c565b82600003610ed457506000610c2a565b6000610ee8670de0b6b3a7640000856113a7565b9050610f08670de0b6b3a7640000610f0086846113be565b146005610c9c565b610f1283826113be565b915050610c2a565b600054610100900460ff16610f415760405162461bcd60e51b8152600401610699906113e0565b61074533610c30565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b828054828255906000526020600020908101928215611002579160200282015b8281111561100257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610fcd565b5061100e929150611012565b5090565b5b8082111561100e5760008155600101611013565b6001600160a01b03811681146107be57600080fd5b60006020828403121561104e57600080fd5b8135610d3b81611027565b60008151808452602080850194506020840160005b838110156110935781516001600160a01b03168752958201959082019060010161106e565b509495945050505050565b6020815260008251604060208401526110ba6060840182611059565b90506020840151601f198483030160408501526110d78282611059565b95945050505050565b6000806000606084860312156110f557600080fd5b833561110081611027565b9250602084013561111081611027565b9150604084013561112081611027565b809150509250925092565b60006020828403121561113d57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561118357611183611144565b604052919050565b600067ffffffffffffffff8211156111a5576111a5611144565b5060051b60200190565b600082601f8301126111c057600080fd5b815160206111d56111d08361118b565b61115a565b8083825260208201915060208460051b8701019350868411156111f757600080fd5b602086015b8481101561121c57805161120f81611027565b83529183019183016111fc565b509695505050505050565b60008060006060848603121561123c57600080fd5b835167ffffffffffffffff8082111561125457600080fd5b611260878388016111af565b945060209150818601518181111561127757600080fd5b86019050601f8101871361128a57600080fd5b80516112986111d08261118b565b81815260059190911b820183019083810190898311156112b757600080fd5b928401925b828410156112d5578351825292840192908401906112bc565b8096505050505050604084015190509250925092565b6000602082840312156112fd57600080fd5b815167ffffffffffffffff81111561131457600080fd5b610c26848285016111af565b634e487b7160e01b600052601160045260246000fd5b81810381811115610c2a57610c2a611320565b634e487b7160e01b600052603260045260246000fd5b60006001820161137157611371611320565b5060010190565b6000825160005b81811015611399576020818601810151858301520161137f565b506000920191825250919050565b8082028115828204841417610c2a57610c2a611320565b6000826113db57634e487b7160e01b600052601260045260246000fd5b500490565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220129abf25519126b9563c2706db767de067ebd1faabcb5e8d1dc46242de0f30b664736f6c63430008160033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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