ETH Price: $2,629.45 (+6.54%)

Contract

0x969C65552B3e980b6566A7C68759E7BaE8c0068d
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x6121ca61185970552023-11-18 6:48:59331 days ago1700290139IN
 Create: AuraLibPub
0 ETH0.0364119818.95364661

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

Contract Source Code Verified (Exact Match)

Contract Name:
AuraLibPub

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 20 : AuraLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

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

import "../interfaces/aura/IAuraBooster.sol";
import "../interfaces/aura/IBaseRewards.sol";
import "../interfaces/aura/IAuraClaimZapV3.sol";
import "../libraries/BalancerLib.sol";
import "../interfaces/aura/IStaker.sol";
import "../strategies/Aura/ConfigAaveBalAura.sol";

library AuraLibPub {
  using SafeERC20 for IERC20;

  /******************************************************
   *                                                    *
   *                  ACTIONS FUNCTIONS                 *
   *                                                    *
   ******************************************************/
  
  function harvest(address _booster, address _auraClaimZapV3, uint256 _pid) external {
    (,,,address rewardContract,,) = IAuraBooster(_booster).poolInfo(_pid);
    uint256 extraRewardsLength = IBaseRewards(rewardContract).extraRewardsLength();
    address[] memory extraRewardContracts = new address[](extraRewardsLength);

    for(uint256 i = 0; i < extraRewardsLength;) {
      extraRewardContracts[i] = IBaseRewards(rewardContract).extraRewards(i);
      unchecked { ++i; }
    }

    address[] memory rewardContracts = new address[](1);
    rewardContracts[0] = rewardContract;
    IAuraClaimZapV3(_auraClaimZapV3).claimRewards(
      rewardContracts,
      extraRewardContracts,
      new address[](0),
      new address[](0),
      IAuraClaimZapV3.ClaimRewardsAmounts(0, 0, 0, 0),
      IAuraClaimZapV3.Options(false, false, false, false, false, false, false)
    );
  }

  // Remove liquidity from Aura and Balancer
  function removeLiqAuraBal2Pools(
    Config.Data memory config,
    uint256 _withdrawMin,
    uint256 _stakedWithdrawAmount
  ) external {
    IBaseRewards(config.auraContracts.stakingToken).withdraw(_stakedWithdrawAmount, false); // TODO: maybe claim should be true
    IAuraBooster(config.auraContracts.booster).withdraw(config.poolIds.pidAura, _stakedWithdrawAmount);

    // Remove liquidity from Balancer (Pool 2)
    uint256 bptPool1Amount = BalancerLib.getTokenOutGivenExactBptInStable(
      config.balancerContracts.balancerVault, 
      config.poolIds.poolId2, 
      config.balancerContracts.bptPool1, 
      config.balancerContracts.bptPool2, 
      type(uint).max
    );
    BalancerLib.balancerExit(
      config.balancerContracts.balancerVault, 
      config.poolIds.poolId2, 
      config.balancerContracts.bptPool1, 
      IERC20(config.balancerContracts.bptPool2).balanceOf(address(this)), 
      bptPool1Amount * _withdrawMin / 1 ether
    );

    // Remove liquidity from Balancer (Pool 1)
    uint256[] memory withdrawAmounts = BalancerLib.getTokensOutGivenExactBptInWeighted(
      config.balancerContracts.balancerVault, 
      config.poolIds.poolId1, 
      config.balancerContracts.bptPool1, 
      type(uint).max
    );

    uint256[] memory minAmounts = new uint256[](2);
    minAmounts[0] = withdrawAmounts[0] * _withdrawMin / 1 ether;
    minAmounts[1] = withdrawAmounts[1] * _withdrawMin / 1 ether;

    BalancerLib.balancerExitMany(
      config.balancerContracts.balancerVault, 
      config.poolIds.poolId1, 
      IERC20(config.balancerContracts.bptPool1).balanceOf(address(this)), 
      minAmounts
    );
  }

  function calcRemoveLiqAuraBal2Pools(
    address _vault,
    bytes32 _pid1,
    bytes32 _pid2,
    address _bptPool1,
    address _bptPool2,
    uint256 _stakedWithdrawAmount
  ) public view returns(uint256[] memory withdrawAmounts) {
    uint256 bptPool1Amount = BalancerLib.getTokenOutGivenExactBptInStable(_vault, _pid2, _bptPool1, _bptPool2, _stakedWithdrawAmount);
    withdrawAmounts = BalancerLib.getTokensOutGivenExactBptInWeighted(_vault, _pid1, _bptPool1, bptPool1Amount);
  }

  /******************************************************
   *                                                    *
   *                    VIEW FUNCTIONS                  *
   *                                                    *
   ******************************************************/

  // Get total underlying liquidity on Aura
  function getUnderlyingAuraBal2Pools(
    address _bptPool1,
    address _bptPool2,
    address _stakingToken,
    bytes32 _poolId1,
    bytes32 _poolId2,
    address _vault
  ) external view returns(uint256, uint256) {
    uint256 bptPool2Amount = IERC20(_stakingToken).balanceOf(address(this));

    uint256[] memory withdrawAmounts = calcRemoveLiqAuraBal2Pools(
      _vault,
      _poolId1,
      _poolId2,
      _bptPool1,
      _bptPool2,
      bptPool2Amount
    );

    return (withdrawAmounts[0], withdrawAmounts[1]);
  }
}

library AuraLib {
  function harvest(address _booster, address _auraClaimZapV3, uint256 _pid) internal {
    AuraLibPub.harvest(_booster, _auraClaimZapV3, _pid);
  }

  function removeLiqAuraBal2Pools(
    Config.Data memory config,
    uint256 _withdrawMin,
    uint256 _stakedWithdrawAmount
  ) internal {
    return AuraLibPub.removeLiqAuraBal2Pools(
      config,
      _withdrawMin,
      _stakedWithdrawAmount
    );
  }

  function getUnderlyingAuraBal2Pools(
    address _bptPool1,
    address _bptPool2,
    address _stakingToken,
    bytes32 _poolId1,
    bytes32 _poolId2,
    address _vault
  ) internal view returns(uint256, uint256) {
    return AuraLibPub.getUnderlyingAuraBal2Pools(
      _bptPool1,
      _bptPool2,
      _stakingToken,
      _poolId1,
      _poolId2,
      _vault
    );
  }
}

File 2 of 20 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

File 3 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

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

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

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

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

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

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

File 4 of 20 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

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

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

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

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

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

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

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

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

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

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

File 5 of 20 : Address.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 Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * 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);
        }
    }
}

File 6 of 20 : IAuraBooster.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAuraBooster {
    function deposit(uint256 pid, uint256 amount, bool stake) external returns (bool);
    function withdraw(uint256 _pid, uint256 _amount) external returns(bool);
    function earmarkRewards(uint256 _pid) external;
    function poolInfo(uint256 pid) external view returns (
        address lptoken,
        address token,
        address gauge,
        address crvRewards,
        address stash,
        bool shutdown
    );
    function staker() external view returns(address);
}

File 7 of 20 : IAuraClaimZapV3.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IAuraClaimZapV3 {
  /**
   * @dev Claim rewards amounts.
   * - depositCrvMaxAmount    The max amount of CRV to deposit if converting to crvCvx
   * - minAmountOut           The min amount out for crv:cvxCrv swaps if swapping. Set this to zero if you
   *                          want to use CrvDepositor instead of balancer swap
   * - depositCvxMaxAmount    The max amount of CVX to deposit if locking CVX
   * - depositCvxCrvMaxAmount The max amount of CVXCVR to stake.
   */
  struct ClaimRewardsAmounts {
    uint256 depositCrvMaxAmount;
    uint256 minAmountOut;
    uint256 depositCvxMaxAmount;
    uint256 depositCvxCrvMaxAmount;
  }

  /**
   * @dev options.
   * - claimCvxCrv             Flag: claim from the cvxCrv rewards contract
   * - claimLockedCvx          Flag: claim from the cvx locker contract
   * - lockCvxCrv              Flag: pull users cvxCrvBalance ready for locking
   * - lockCrvDeposit          Flag: locks crv rewards as cvxCrv
   * - useAllWalletFunds       Flag: lock rewards and existing balance
   * - useCompounder           Flag: deposit cvxCrv into autocompounder
   * - lockCvx                 Flag: lock cvx rewards in locker
   */
  struct Options {
    bool claimCvxCrv;
    bool claimLockedCvx;
    bool lockCvxCrv;
    bool lockCrvDeposit;
    bool useAllWalletFunds;
    bool useCompounder;
    bool lockCvx;
  }

  /**
   * @notice Claim all the rewards
   * @param rewardContracts        Array of addresses for LP token rewards
   * @param extraRewardContracts   Array of addresses for extra rewards
   * @param tokenRewardContracts   Array of addresses for token rewards e.g vlCvxExtraRewardDistribution
   * @param tokenRewardTokens      Array of token reward addresses to use with tokenRewardContracts
   * @param amounts                Claim rewards amounts.
   * @param options                Claim options
   */
  function claimRewards(
    address[] calldata rewardContracts,
    address[] calldata extraRewardContracts,
    address[] calldata tokenRewardContracts,
    address[] calldata tokenRewardTokens,
    ClaimRewardsAmounts calldata amounts,
    Options calldata options
  ) external;
}

File 8 of 20 : IBaseRewards.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IBaseRewards {
  function extraRewardsLength() external view returns (uint256);
  function extraRewards(uint256 index) external view returns(address);
  function rewardToken() external view returns(address);
  function earned(address account) external view returns(uint256);
  function withdrawAndUnwrap(uint256 amount, bool claim) external returns(bool);
  function withdraw(uint256 amount, bool claim) external returns(bool);
}

File 9 of 20 : IStaker.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStaker {
  function balanceOfPool(address _gauge) external view returns(uint256);
}

File 10 of 20 : IStablePool.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStablePool {
  function getLastInvariant() external view returns(uint256, uint256);
  function getSwapFeePercentage() external view returns(uint256);
  function totalSupply() external view returns(uint256);
  function getVault() external view returns (address);
  function getPoolId() external view returns (bytes32);
}

File 11 of 20 : IBalancerVault.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.9.0;
pragma experimental ABIEncoderV2;

interface IBalancerVault {
    struct SingleSwap {
        bytes32 poolId;
        SwapKind kind;
        address assetIn;
        address assetOut;
        uint256 amount;
        bytes userData;
    }

    struct BatchSwapStep {
        bytes32 poolId;
        uint256 assetInIndex;
        uint256 assetOutIndex;
        uint256 amount;
        bytes userData;
    }

    struct FundManagement {
        address sender;
        bool fromInternalBalance;
        address payable recipient;
        bool toInternalBalance;
    }

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

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

    enum SwapKind { GIVEN_IN, GIVEN_OUT }

    function swap(
        SingleSwap memory singleSwap,
        FundManagement memory funds,
        uint256 limit,
        uint256 deadline
    ) external payable returns (uint256);

    function batchSwap(
        SwapKind kind,
        BatchSwapStep[] memory swaps,
        address[] memory assets,
        FundManagement memory funds,
        int256[] memory limits,
        uint256 deadline
    ) external returns (int256[] memory assetDeltas);

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

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

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

    function getPool(bytes32 poolId)
        external
        view
        returns (address, uint8);

    function flashLoan(
        address recipient,
        address[] memory tokens,
        uint256[] memory amounts,
        bytes memory userData
    ) external;
    
    function queryBatchSwap(
       SwapKind kind,
       BatchSwapStep[] memory swaps,
       address[] memory assets,
       FundManagement memory funds
    ) external returns (int256[] memory);

}

File 12 of 20 : BalancerLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

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

import "../interfaces/beethovenx/IBalancerVault.sol";
import "../interfaces/balancer/IStablePool.sol";
import "../strategies/Balancer/WeightedMath.sol";
import "../strategies/Balancer/BeefyBalancerStructs.sol";
import "../strategies/Balancer/StableMath.sol";

library BalancerLibPub {
  function balancerJoin(address _vault, bytes32 _poolId, address _tokenIn, uint256 _amountIn) external {
    BalancerLib.balancerJoin(_vault, _poolId, _tokenIn, _amountIn);
  }

  function balancerJoinMany(address _vault, bytes32 _poolId, uint256[] memory _amountsIn) external {
    BalancerLib.balancerJoinMany(_vault, _poolId, _amountsIn);
  }

  function balancerSwap(
      BalancerLib.SwapParams memory params,
      IBalancerVault.FundManagement memory funds,
      IBalancerVault.SwapKind swapKind
  ) external returns (uint256) {
    return BalancerLib.balancerSwap(params, funds, swapKind);
  }

  function balancerBatchSwap(address _vault, IBalancerVault.SwapKind _swapKind, address[] memory _route, bytes32[] memory pools, IBalancerVault.FundManagement memory _funds, uint256 _amountIn) internal returns (int256[] memory) {
    return BalancerLib.balancerBatchSwap(_vault, _swapKind, _route, pools, _funds, _amountIn);
  }

  function balancerBatchQuote(address _vault, IBalancerVault.SwapKind _swapKind, address[] memory _route, bytes32[] memory pools, IBalancerVault.FundManagement memory _funds, uint256 _amountIn) internal returns (int256[] memory) {
    return BalancerLib.balancerBatchQuote(_vault, _swapKind, _route, pools, _funds, _amountIn);
  }
}

library BalancerLib {
    using SafeERC20 for IERC20;

    struct SwapParams {
        address vault;
        bytes32 poolId; 
        address tokenIn; 
        address tokenOut; 
        uint256 amountIn;
	  }

    /******************************************************
     *                                                    *
     *                  ACTIONS FUNCTIONS                 *
     *                                                    *
     ******************************************************/

    function balancerJoin(address _vault, bytes32 _poolId, address _tokenIn, uint256 _amountIn) internal {
        (address[] memory lpTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);
        uint256[] memory amounts = new uint256[](lpTokens.length);
        for (uint256 i = 0; i < amounts.length;) {
            amounts[i] = lpTokens[i] == _tokenIn ? _amountIn : 0;
            unchecked { ++i; }
        }
        bytes memory userData = abi.encode(1, amounts, 1);

        IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(lpTokens, amounts, userData, false);
        IBalancerVault(_vault).joinPool(_poolId, address(this), address(this), request);
    }

    function balancerExit(address _vault, bytes32 _poolId, address _tokenOut, uint256 bptAmountIn, uint256 _minAmountOut) internal {
        (address[] memory lpTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);
        uint256[] memory amounts = new uint256[](lpTokens.length);
        for (uint256 i = 0; i < amounts.length;) {
            amounts[i] = lpTokens[i] == _tokenOut ? _minAmountOut : 0;
            unchecked { ++i; }
        }

        bytes memory userData = abi.encode(0, bptAmountIn, 0);

        IBalancerVault.ExitPoolRequest memory request = IBalancerVault.ExitPoolRequest(lpTokens, amounts, userData, false);
        IBalancerVault(_vault).exitPool(_poolId, address(this), payable(address(this)), request);
    }
    
    function balancerJoinMany(address _vault, bytes32 _poolId, uint256[] memory _amountsIn) internal {
        (address[] memory lpTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);
   
        bytes memory userData = abi.encode(1, _amountsIn, 1);

        IBalancerVault.JoinPoolRequest memory request = IBalancerVault.JoinPoolRequest(lpTokens, _amountsIn, userData, false);
        IBalancerVault(_vault).joinPool(_poolId, address(this), address(this), request);
    }

    function balancerExitMany(address _vault, bytes32 _poolId, uint256 bptAmountIn, uint256[] memory _minAmountsOut) internal {
        (address[] memory lpTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);

        bytes memory userData = abi.encode(1, bptAmountIn);

        IBalancerVault.ExitPoolRequest memory request = IBalancerVault.ExitPoolRequest(lpTokens, _minAmountsOut, userData, false);
        IBalancerVault(_vault).exitPool(_poolId, address(this), payable(address(this)), request);
    }


    // Swap funds on Balancer
    function balancerSwap(
        SwapParams memory params,
        IBalancerVault.FundManagement memory funds,
        IBalancerVault.SwapKind swapKind
    ) internal returns (uint256) {
      IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap(params.poolId, swapKind, params.tokenIn, params.tokenOut, params.amountIn, "");
      return IBalancerVault(params.vault).swap(singleSwap, funds, 1, block.timestamp);
    }

    function balancerBatchSwap(address _vault, IBalancerVault.SwapKind _swapKind, address[] memory _route, bytes32[] memory pools, IBalancerVault.FundManagement memory _funds, uint256 _amountIn) internal returns (int256[] memory) {
      IBalancerVault.BatchSwapStep[] memory _swaps = new IBalancerVault.BatchSwapStep[](_route.length - 1); 
      int256[] memory limits = new int256[](_route.length);
      require(_route.length > 1, "Too short route");
      require(pools.length + 1 >= _route.length, "Too short pools");
      for (uint i; i < _route.length; i++) {
          if (i == 0) {
              limits[0] = int(_amountIn);
          }
          
          if (i == _route.length - 1) {
              limits[i] = 0; // TODO: it was -1, must be reviewed
          } else {
              _swaps[i] = IBalancerVault.BatchSwapStep({
                poolId: pools[i],
                assetInIndex: i,
                assetOutIndex: i + 1,
                amount: i == 0 ? _amountIn : 0,
                userData: ""
            });
          }
      }
      return IBalancerVault(_vault).batchSwap(_swapKind, _swaps, _route, _funds, limits, block.timestamp);
    }

  /******************************************************
   *                                                    *
   *                    VIEW FUNCTIONS                  *
   *                                                    *
   ******************************************************/

   // Get Balancer pool token balances
  function getPoolBalances(address _vault, bytes32 _poolId) internal view returns(uint256[] memory) {
    (,uint256[] memory balances,) = IBalancerVault(_vault).getPoolTokens(_poolId);
    return balances;
  }

  // Get Token index
  function getPoolTokenIndex(address _vault, bytes32 _poolId, address _token) internal view returns(uint256) {
    (address[] memory poolTokens,,) = IBalancerVault(_vault).getPoolTokens(_poolId);
    for (uint256 i = 0; i < poolTokens.length;) {
      if(poolTokens[i] == _token) {
        return i;
      }
      unchecked { ++i; }
    }
    revert("index not found");
  }

  // Get Balancer single amount to withdraw from Stable Pool from exact BPT amount
  function getTokenOutGivenExactBptInStable(address _vault, bytes32 _poolId, address _token, address _bptPool, uint lpBalance) internal view returns(uint256) {
    if (lpBalance == type(uint).max) {
      lpBalance = IERC20(_bptPool).balanceOf(address(this));
    }
    
    uint256[] memory poolTokenBalances = getPoolBalances(_vault, _poolId);
    (, uint256 amp) = IStablePool(_bptPool).getLastInvariant();
    uint256 invariant = StableMath._calculateInvariant(amp, poolTokenBalances);
    uint256 totalSupply = IStablePool(_bptPool).totalSupply();
    uint256 index = getPoolTokenIndex(_vault, _poolId, _token);
    uint256 swapFeePercentage = IStablePool(_bptPool).getSwapFeePercentage();

    return StableMath._calcTokenOutGivenExactBptIn(amp, poolTokenBalances, index, lpBalance, totalSupply, invariant, swapFeePercentage);
  }

  // Get Balancer amounts to withdraw from Weighted pools from exact BPT amount
  function getTokensOutGivenExactBptInWeighted(address _vault, bytes32 _poolId, address _bptPool, uint lpBalance) internal view returns(uint256[] memory) {
    if (lpBalance == type(uint).max) {
      lpBalance = IERC20(_bptPool).balanceOf(address(this));
    }
    
    uint256[] memory poolTokenBalances = getPoolBalances(_vault, _poolId);
    uint256 totalSupply = IStablePool(_bptPool).totalSupply();

    return WeightedMath._calcTokensOutGivenExactBptIn(poolTokenBalances, lpBalance, totalSupply);
  }

  function getPoolAddress(bytes32 poolId) internal pure returns (address) {
    // 12 byte logical shift left to remove the nonce and specialization setting. We don't need to mask,
    // since the logical shift already sets the upper bits to zero.
    return address(bytes20(poolId));
  }

  function balancerBatchQuote(address _vault, IBalancerVault.SwapKind _swapKind, address[] memory _route, bytes32[] memory pools, IBalancerVault.FundManagement memory _funds, uint256 _amountIn) internal returns (int256[] memory) {
    IBalancerVault.BatchSwapStep[] memory _swaps = new IBalancerVault.BatchSwapStep[](_route.length - 1); 
    require(_route.length > 1, "Too short route");
    require(pools.length + 1 >= _route.length, "Too short pools");
    for (uint i; i < _route.length; i++) {          
        if (i < _route.length - 1) {
            _swaps[i] = IBalancerVault.BatchSwapStep({
              poolId: pools[i],
              assetInIndex: i,
              assetOutIndex: i + 1,
              amount: i == 0 ? _amountIn : 0,
              userData: ""
          });
        }
    }
    return IBalancerVault(_vault).queryBatchSwap(_swapKind, _swaps, _route, _funds);
  }

}

File 13 of 20 : ConfigAaveBalAura.sol
pragma solidity ^0.8.0;

import "../../interfaces/beethovenx/IBalancerVault.sol";

uint constant WANT_INDEX = 2;
uint constant INTEREST_RATE_MODE = 2;
uint8 constant BASE_TOKENS_COUNT = 3;

interface Config {
  struct Data {
    address loanToken0;
    address loanToken1;
    address want;
    bytes32 decimals;
    uint nativeIndex;

    uint proportion;
    uint borrowRate;

    AaveContracts aaveContracts;
    BalancerContracts balancerContracts;
    AuraContracts auraContracts;
    PoolIds poolIds;
  }

  struct AaveContracts {
    address lendingPool; // Aave lending pool
    address priceOracle; // Aave price oracle
    address dataProvider; // Aave data provider
    address rewardsController; // Aave rewards controller
  }

  struct BalancerContracts {
    address balancerVault; // Balancer Vault
    address bptPool1; // balancer LP
    address bptPool2; // balancer LP
  }

  struct AuraContracts {
    address booster; // Aura booster
    address auraClaimZapV3; // Aura rewards claimer
    address stakingToken; // Aura staking token
  }

  struct PoolIds {
    bytes32 poolId1; // Balancer pool Id
    bytes32 poolId2; // Balancer pool Id
    uint256 pidAura; // Aura staking pool id
  }

  // struct getter
  function get() external view returns (Data memory);
}

interface ConfigExt {
  struct Data {
    address[] tokens;
    bytes32[] routing; // routing[sourceTokenIndex][targetTokenIndex] = nextTokenIndex or (poolIndex + tokensCount)
                       // routing[poolIndex + tokensCount] = poolId
    address[] rewardersAura;
    bytes32 rewardTokens; // tokenIndexesAura | tokenIndexesAave, last byte is length 
    bool harvestOnDeposit;
    uint withdrawMin; // min rate to be withdrawn from Balancer
  }

  function get() external view returns (Data memory);
}

struct Configs {
  Config.Data base;
  ConfigExt.Data ext;
}

function getRoute(Configs memory configs, uint tokenInIndex, uint tokenOutIndex) pure returns (uint[] memory path, bytes32[] memory pools) {
  (path, pools) = buildRoute(configs.ext, tokenInIndex, tokenOutIndex, 1);
  path[0] = tokenInIndex;
}

function buildRoute(ConfigExt.Data memory configExt, uint tokenInIndex, uint tokenOutIndex, uint depth) pure returns (uint[] memory path, bytes32[] memory pools) {
  unchecked {
    bytes32 route = configExt.routing[tokenInIndex];
    uint step = uint8(route[tokenOutIndex]);
    uint poolIndex;
    uint tokenIndex;
    if (step < configExt.tokens.length + BASE_TOKENS_COUNT) {
      tokenIndex = step;
      poolIndex = uint8(route[tokenIndex]);
      (path, pools) = buildRoute(configExt, tokenIndex, tokenOutIndex, depth + 1);
    } else {
      require(step < type(uint8).max, "No route found");
      tokenIndex = tokenOutIndex;
      poolIndex = step;
      path = new uint[](depth + 1);
      pools = new bytes32[](depth);
    }

    path[depth] = tokenIndex;
    pools[depth - 1] = configExt.routing[poolIndex];
  }
}

function getProportion(Configs memory configs, uint tokenIndex) pure returns (uint) {
  if (tokenIndex == 0) {
    return configs.base.proportion;
  }
  if (tokenIndex == 1) {
    return 1 ether - configs.base.proportion;
  }
  revert("Proportion not found");
}

function getTokenAddress(Configs memory configs, uint tokenIndex) pure returns (address) {
  if (tokenIndex == 0) {
    return configs.base.loanToken0;
  }
  if (tokenIndex == 1) {
    return configs.base.loanToken1;
  }
  if (tokenIndex == WANT_INDEX) {
    return configs.base.want;
  }

  return configs.ext.tokens[tokenIndex - BASE_TOKENS_COUNT];
}

function getTokenIndex(Configs memory configs, address tokenAddress) pure returns (uint tokenIndex) {
  unchecked {
    for(tokenIndex = 0; tokenIndex < BASE_TOKENS_COUNT + configs.ext.tokens.length; tokenIndex++) {
      if (getTokenAddress(configs, tokenIndex) == tokenAddress) {
        return tokenIndex;
      }
    }

    revert("Token not found");
  }
}

function getRouteAddresses(Configs memory configs, uint tokenInIndex, uint tokenOutIndex) pure returns (address[] memory tokens, bytes32[] memory pools) {
  uint[] memory route;
  (route, pools) = getRoute(configs, tokenInIndex, tokenOutIndex);
  tokens = new address[](route.length);
  unchecked {
    for(uint i = 0; i < route.length; i++) {
      tokens[i] = getTokenAddress(configs, route[i]);
    }
  }
}

function getRewardTokensCount(Configs memory configs) pure returns (uint) {
  return uint8(uint(configs.ext.rewardTokens));
}

function getRewardToken(Configs memory configs, uint rewardTokenIndex) pure returns (uint) {
  return uint8(configs.ext.rewardTokens[rewardTokenIndex]);
}

File 14 of 20 : 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.7.1 <0.9.0;

// 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 Errors {
    // 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;
    uint256 internal constant INSUFFICIENT_DATA = 105;

    // 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;
    uint256 internal constant ADD_OR_REMOVE_BPT = 354;
    uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355;
    uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356;
    uint256 internal constant MALICIOUS_QUERY_REVERT = 357;
    uint256 internal constant JOINS_EXITS_DISABLED = 358;

    // 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;
    uint256 internal constant BURN_FROM_ZERO = 444;

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

    // FeeSplitter
    uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700;

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

File 15 of 20 : BeefyBalancerStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

library BeefyBalancerStructs {
    struct BatchSwapStruct {
        bytes32 poolId;
        uint256 assetInIndex;
        uint256 assetOutIndex;
    }

    struct Reward {
        mapping(uint => BatchSwapStruct) swapInfo;
        address[] assets;
        bytes routeToNative; // backup route in case there is no Balancer liquidity for reward
        uint minAmount; // minimum amount to be swapped to native
    }

     struct Input {
        address input;
        bool isComposable;
        bool isBeets;
    }
}

File 16 of 20 : 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 "./LogExpMath.sol";
import "./BalancerErrors.sol";

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

library FixedPoint {
    uint256 internal constant ONE = 1e18; // 18 decimal places
    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, Errors.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, Errors.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, Errors.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, Errors.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, Errors.ZERO_DIVISION);

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

            return aInflated / b;
        }
    }

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

        if (a == 0) {
            return 0;
        } else {
            uint256 aInflated = a * ONE;
            _require(aInflated / a == ONE, Errors.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) {
        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) {
        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 17 of 20 : 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 */

/**
 * @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 < 2**255, Errors.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, Errors.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,
            Errors.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, Errors.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, Errors.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 18 of 20 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./BalancerErrors.sol";

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow checks.
 * Adapted from OpenZeppelin's SafeMath library
 */
library Math {
    /**
     * @dev Returns the addition of two unsigned integers of 256 bits, reverting on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        _require(c >= a, Errors.ADD_OVERFLOW);
        return c;
    }

    /**
     * @dev Returns the addition of two signed integers, reverting on overflow.
     */
    function add(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a + b;
        _require((b >= 0 && c >= a) || (b < 0 && c < a), Errors.ADD_OVERFLOW);
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        _require(b <= a, Errors.SUB_OVERFLOW);
        uint256 c = a - b;
        return c;
    }

    /**
     * @dev Returns the subtraction of two signed integers, reverting on overflow.
     */
    function sub(int256 a, int256 b) internal pure returns (int256) {
        int256 c = a - b;
        _require((b >= 0 && c <= a) || (b < 0 && c > a), Errors.SUB_OVERFLOW);
        return c;
    }

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

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

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a * b;
        _require(a == 0 || c / a == b, Errors.MUL_OVERFLOW);
        return c;
    }

    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        _require(b != 0, Errors.ZERO_DIVISION);
        return a / b;
    }

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

        if (a == 0) {
            return 0;
        } else {
            return 1 + (a - 1) / b;
        }
    }
}

File 19 of 20 : StableMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

import "./FixedPoint.sol";
import "./Math.sol";
import "./BalancerErrors.sol";

library StableMath {
  using FixedPoint for uint256;

  uint256 internal constant _AMP_PRECISION = 1e3;
  
  function _calcTokenOutGivenExactBptIn(
    uint256 amp,
    uint256[] memory balances,
    uint256 tokenIndex,
    uint256 bptAmountIn,
    uint256 bptTotalSupply,
    uint256 currentInvariant,
    uint256 swapFeePercentage
  ) internal pure returns (uint256) {
    // Token out, so we round down overall.

    uint256 newInvariant = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply).mulUp(currentInvariant);

    // Calculate amount out without fee
    uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances(
      amp,
      balances,
      newInvariant,
      tokenIndex
    );
    uint256 amountOutWithoutFee = balances[tokenIndex].sub(newBalanceTokenIndex);

    // First calculate the sum of all token balances, which will be used to calculate
    // the current weight of each token
    uint256 sumBalances = 0;
    for (uint256 i = 0; i < balances.length; i++) {
      sumBalances = sumBalances.add(balances[i]);
    }

    // We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result
    // in swap fees.
    uint256 currentWeight = balances[tokenIndex].divDown(sumBalances);
    uint256 taxablePercentage = currentWeight.complement();

    // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it
    // to 'token out'. This results in slightly larger price impact. Fees are rounded up.
    uint256 taxableAmount = amountOutWithoutFee.mulUp(taxablePercentage);
    uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount);

    // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%
    return nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage));
  }

  // This function calculates the balance of a given token (tokenIndex)
    // given all the other balances and the invariant
    function _getTokenBalanceGivenInvariantAndAllOtherBalances(
        uint256 amplificationParameter,
        uint256[] memory balances,
        uint256 invariant,
        uint256 tokenIndex
    ) internal pure returns (uint256) {
        // Rounds result up overall

        uint256 ampTimesTotal = amplificationParameter * balances.length;
        uint256 sum = balances[0];
        uint256 P_D = balances[0] * balances.length;
        for (uint256 j = 1; j < balances.length; j++) {
            P_D = Math.divDown(Math.mul(Math.mul(P_D, balances[j]), balances.length), invariant);
            sum = sum.add(balances[j]);
        }
        // No need to use safe math, based on the loop above `sum` is greater than or equal to `balances[tokenIndex]`
        sum = sum - balances[tokenIndex];

        uint256 inv2 = Math.mul(invariant, invariant);
        // We remove the balance from c by multiplying it
        uint256 c = Math.mul(
            Math.mul(Math.divUp(inv2, Math.mul(ampTimesTotal, P_D)), _AMP_PRECISION),
            balances[tokenIndex]
        );
        uint256 b = sum.add(Math.mul(Math.divDown(invariant, ampTimesTotal), _AMP_PRECISION));

        // We iterate to find the balance
        uint256 prevTokenBalance = 0;
        // We multiply the first iteration outside the loop with the invariant to set the value of the
        // initial approximation.
        uint256 tokenBalance = Math.divUp(inv2.add(c), invariant.add(b));

        for (uint256 i = 0; i < 255; i++) {
            prevTokenBalance = tokenBalance;

            tokenBalance = Math.divUp(
                Math.mul(tokenBalance, tokenBalance).add(c),
                Math.mul(tokenBalance, 2).add(b).sub(invariant)
            );

            if (tokenBalance > prevTokenBalance) {
                if (tokenBalance - prevTokenBalance <= 1) {
                    return tokenBalance;
                }
            } else if (prevTokenBalance - tokenBalance <= 1) {
                return tokenBalance;
            }
        }

        _revert(Errors.STABLE_GET_BALANCE_DIDNT_CONVERGE);
    }

    function _calculateInvariant(uint256 amplificationParameter, uint256[] memory balances)
        internal
        pure
        returns (uint256)
    {
        /**********************************************************************************************
        // invariant                                                                                 //
        // D = invariant                                                  D^(n+1)                    //
        // A = amplification coefficient      A  n^n S + D = A D n^n + -----------                   //
        // S = sum of balances                                             n^n P                     //
        // P = product of balances                                                                   //
        // n = number of tokens                                                                      //
        **********************************************************************************************/

        // Always round down, to match Vyper's arithmetic (which always truncates).

        uint256 sum = 0; // S in the Curve version
        uint256 numTokens = balances.length;
        for (uint256 i = 0; i < numTokens; i++) {
            sum = sum.add(balances[i]);
        }
        if (sum == 0) {
            return 0;
        }

        uint256 prevInvariant; // Dprev in the Curve version
        uint256 invariant = sum; // D in the Curve version
        uint256 ampTimesTotal = amplificationParameter * numTokens; // Ann in the Curve version

        for (uint256 i = 0; i < 255; i++) {
            uint256 D_P = invariant;

            for (uint256 j = 0; j < numTokens; j++) {
                // (D_P * invariant) / (balances[j] * numTokens)
                D_P = Math.divDown(Math.mul(D_P, invariant), Math.mul(balances[j], numTokens));
            }

            prevInvariant = invariant;

            invariant = Math.divDown(
                Math.mul(
                    // (ampTimesTotal * sum) / AMP_PRECISION + D_P * numTokens
                    (Math.divDown(Math.mul(ampTimesTotal, sum), _AMP_PRECISION).add(Math.mul(D_P, numTokens))),
                    invariant
                ),
                // ((ampTimesTotal - _AMP_PRECISION) * invariant) / _AMP_PRECISION + (numTokens + 1) * D_P
                (
                    Math.divDown(Math.mul((ampTimesTotal - _AMP_PRECISION), invariant), _AMP_PRECISION).add(
                        Math.mul((numTokens + 1), D_P)
                    )
                )
            );

            if (invariant > prevInvariant) {
                if (invariant - prevInvariant <= 1) {
                    return invariant;
                }
            } else if (prevInvariant - invariant <= 1) {
                return invariant;
            }
        }

        _revert(Errors.STABLE_INVARIANT_DIDNT_CONVERGE);
    }
}

File 20 of 20 : WeightedMath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; 

import "./FixedPoint.sol";

library WeightedMath {
  using FixedPoint for uint256;
  
  // Invariant shrink limit: non-proportional exits cannot cause the invariant to decrease by less than this ratio.
  uint256 internal constant _MIN_INVARIANT_RATIO = 0.7e18;

  function _calcTokenOutGivenExactBptIn(
    uint256 balance,
    uint256 normalizedWeight,
    uint256 bptAmountIn,
    uint256 bptTotalSupply,
    uint256 swapFeePercentage
  ) internal pure returns (uint256) {
    /*****************************************************************************************
    // exactBPTInForTokenOut                                                                //
    // a = amountOut                                                                        //
    // b = balance                     /      /    totalBPT - bptIn       \    (1 / w)  \   //
    // bptIn = bptAmountIn    a = b * |  1 - | --------------------------  | ^           |  //
    // bpt = totalBPT                  \      \       totalBPT            /             /   //
    // w = weight                                                                           //
    *****************************************************************************************/

    // Token out, so we round down overall. The multiplication rounds down, but the power rounds up (so the base
    // rounds up). Because (totalBPT - bptIn) / totalBPT <= 1, the exponent rounds down.

    // Calculate the factor by which the invariant will decrease after burning BPTAmountIn
    uint256 invariantRatio = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply);
    require(invariantRatio >= _MIN_INVARIANT_RATIO, "balancer: MIN_BPT_IN_FOR_TOKEN_OUT");

    // Calculate by how much the token balance has to decrease to match invariantRatio
    uint256 balanceRatio = invariantRatio.powUp(FixedPoint.ONE.divDown(normalizedWeight));

    // Because of rounding up, balanceRatio can be greater than one. Using complement prevents reverts.
    uint256 amountOutWithoutFee = balance.mulDown(balanceRatio.complement());

    // We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result
    // in swap fees.

    // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it
    // to 'token out'. This results in slightly larger price impact. Fees are rounded up.
    uint256 taxableAmount = amountOutWithoutFee.mulUp(normalizedWeight.complement());
    uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount);
    uint256 taxableAmountMinusFees = taxableAmount.mulUp(swapFeePercentage.complement());

    return nonTaxableAmount.add(taxableAmountMinusFees);
  }

  function _calcTokensOutGivenExactBptIn(
    uint256[] memory balances,
    uint256 bptAmountIn,
    uint256 bptTotalSupply
  ) internal pure returns (uint256[] memory) {
    /**********************************************************************************************
    // exactBPTInForTokensOut                                                                    //
    // (per token)                                                                               //
    // aO = amountOut                  /        bptIn         \                                  //
    // b = balance           a0 = b * | ---------------------  |                                 //
    // bptIn = bptAmountIn             \       totalBPT       /                                  //
    // bpt = totalBPT                                                                            //
    **********************************************************************************************/

    uint256[] memory amounts = new uint256[](balances.length);
    for (uint256 i = 0; i < balances.length;) {
      amounts[i] = balances[i].mulDown(bptAmountIn).divDown(bptTotalSupply);
      unchecked { ++i; }
    }
    return amounts;
  }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"bytes32","name":"_pid1","type":"bytes32"},{"internalType":"bytes32","name":"_pid2","type":"bytes32"},{"internalType":"address","name":"_bptPool1","type":"address"},{"internalType":"address","name":"_bptPool2","type":"address"},{"internalType":"uint256","name":"_stakedWithdrawAmount","type":"uint256"}],"name":"calcRemoveLiqAuraBal2Pools","outputs":[{"internalType":"uint256[]","name":"withdrawAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bptPool1","type":"address"},{"internalType":"address","name":"_bptPool2","type":"address"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"bytes32","name":"_poolId1","type":"bytes32"},{"internalType":"bytes32","name":"_poolId2","type":"bytes32"},{"internalType":"address","name":"_vault","type":"address"}],"name":"getUnderlyingAuraBal2Pools","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6121ca61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806308ed854f1461005b5780639bc9ed5714610088578063c2ceb95f146100a8578063f00449e9146100ca575b600080fd5b61006e610069366004611876565b6100ea565b604080519283526020830191909152015b60405180910390f35b61009b6100963660046118e6565b6101b4565b60405161007f919061194d565b8180156100b457600080fd5b506100c86100c3366004611991565b6101df565b005b8180156100d657600080fd5b506100c86100e5366004611b7e565b6104e2565b6040516370a0823160e01b8152306004820152600090819081906001600160a01b038816906370a0823190602401602060405180830381865afa158015610135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101599190611c68565b9050600061016b8588888d8d876101b4565b90508060008151811061018057610180611c81565b60200260200101518160018151811061019b5761019b611c81565b6020026020010151935093505050965096945050505050565b606060006101c58887878787610862565b90506101d388888784610a54565b98975050505050505050565b604051631526fe2760e01b8152600481018290526000906001600160a01b03851690631526fe279060240160c060405180830381865afa158015610227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024b9190611ca7565b505093505050506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190611c68565b905060008167ffffffffffffffff8111156102d3576102d36119d2565b6040519080825280602002602001820160405280156102fc578160200160208202803683370190505b50905060005b828110156103a557604051632061aa2360e11b8152600481018290526001600160a01b038516906340c3544690602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611d29565b82828151811061038557610385611c81565b6001600160a01b0390921660209283029190910190910152600101610302565b506040805160018082528183019092526000916020808301908036833701905050905083816000815181106103dc576103dc611c81565b6001600160a01b039283166020918202929092010152861663d34640b282846000604051908082528060200260200182016040528015610426578160200160208202803683370190505b5060408051600080825260a08083018452602080840183815284860184905260608086018590526080808701869052875160e08082018a52878252948101879052808901879052918201869052810185905292830184905260c083019390935293519388901b6001600160e01b03191684526104a796959493600401611d8a565b600060405180830381600087803b1580156104c157600080fd5b505af11580156104d5573d6000803e3d6000fd5b5050505050505050505050565b6101208301516040908101519051631c683a1b60e11b815260048101839052600060248201526001600160a01b03909116906338d07436906044016020604051808303816000875af115801561053c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105609190611e6f565b50610120830151516101408401516040908101519051630441a3e760e41b81526001600160a01b039092169163441a3e70916105a9918590600401918252602082015260400190565b6020604051808303816000875af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190611e6f565b50600061062284610100015160000151856101400151602001518661010001516020015187610100015160400151600019610862565b61010085015180516101408701516020908101519083015160409384015193516370a0823160e01b81523060048201529495506106d5949293919290916001600160a01b0316906370a0823190602401602060405180830381865afa15801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190611c68565b670de0b6b3a76400006106c68988611ea0565b6106d09190611eb7565b610b56565b6101008401518051610140860151516020909201516000926106fa9291600019610a54565b6040805160028082526060820183529293506000929091602083019080368337019050509050670de0b6b3a7640000858360008151811061073d5761073d611c81565b602002602001015161074f9190611ea0565b6107599190611eb7565b8160008151811061076c5761076c611c81565b602002602001018181525050670de0b6b3a7640000858360018151811061079557610795611c81565b60200260200101516107a79190611ea0565b6107b19190611eb7565b816001815181106107c4576107c4611c81565b60209081029190910181019190915261010087015180516101408901515191909201516040516370a0823160e01b815230600482015261085a9392916001600160a01b0316906370a0823190602401602060405180830381865afa158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190611c68565b84610d37565b505050505050565b600060001982036108d8576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d59190611c68565b91505b60006108e48787610e21565b90506000846001600160a01b0316639b02cdde6040518163ffffffff1660e01b81526004016040805180830381865afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109499190611ed9565b91505060006109588284610ea0565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611c68565b905060006109cd8b8b8b611056565b90506000886001600160a01b03166355c676286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a339190611c68565b9050610a448587848b878987611161565b9c9b505050505050505050505050565b60606000198203610aca576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190611c68565b91505b6000610ad68686610e21565b90506000846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3c9190611c68565b9050610b498285836112a6565b925050505b949350505050565b604051631f29a8cd60e31b8152600481018590526000906001600160a01b0387169063f94d466890602401600060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bc69190810190611f8c565b505090506000815167ffffffffffffffff811115610be657610be66119d2565b604051908082528060200260200182016040528015610c0f578160200160208202803683370190505b50905060005b8151811015610c7e57856001600160a01b0316838281518110610c3a57610c3a611c81565b60200260200101516001600160a01b031614610c57576000610c59565b835b828281518110610c6b57610c6b611c81565b6020908102919091010152600101610c15565b50604080516000602082018190529181018690526060810182905260800160408051601f1981840301815260808301825285835260208301859052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b038a1690638bdb391390610cfa908b903090819087906004016120a0565b600060405180830381600087803b158015610d1457600080fd5b505af1158015610d28573d6000803e3d6000fd5b50505050505050505050505050565b604051631f29a8cd60e31b8152600481018490526000906001600160a01b0386169063f94d466890602401600060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da79190810190611f8c565b5050604080516001602082015290810185905290915060009060600160408051601f1981840301815260808301825284835260208301869052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b03881690638bdb3913906104a79089903090819087906004016120a0565b604051631f29a8cd60e31b8152600481018290526060906000906001600160a01b0385169063f94d466890602401600060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e949190810190611f8c565b50925050505b92915050565b80516000908190815b81811015610ef157610edd858281518110610ec657610ec6611c81565b60200260200101518461136090919063ffffffff16565b925080610ee981612155565b915050610ea9565b5081600003610f0557600092505050610e9a565b60008281610f138489611ea0565b905060005b60ff81101561103f578260005b86811015610f7657610f62610f3a838761137d565b610f5d8c8481518110610f4f57610f4f611c81565b60200260200101518a61137d565b6113ab565b915080610f6e81612155565b915050610f25565b50839450610fdd610fae610fa8610f8d848a61137d565b610fa2610f9a888d61137d565b6103e86113ab565b90611360565b8661137d565b610f5d610fc5610fbf8a600161216e565b8561137d565b610fa2610f9a610fd76103e88a612181565b8a61137d565b93508484111561100c576001610ff38686612181565b116110075783975050505050505050610e9a565b61102c565b60016110188587612181565b1161102c5783975050505050505050610e9a565b508061103781612155565b915050610f18565b5061104b6101416113c4565b505050505092915050565b604051631f29a8cd60e31b81526004810183905260009081906001600160a01b0386169063f94d466890602401600060405180830381865afa1580156110a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c89190810190611f8c565b5050905060005b815181101561111b57836001600160a01b03168282815181106110f4576110f4611c81565b60200260200101516001600160a01b03160361111357915061115a9050565b6001016110cf565b5060405162461bcd60e51b815260206004820152600f60248201526e1a5b99195e081b9bdd08199bdd5b99608a1b604482015260640160405180910390fd5b9392505050565b6000806111828461117c87611176818b6113d7565b906113f3565b9061146f565b905060006111928a8a848b6114ba565b905060006111c2828b8b815181106111ac576111ac611c81565b60200260200101516113d790919063ffffffff16565b90506000805b8b51811015611211576111fd8c82815181106111e6576111e6611c81565b60200260200101518361136090919063ffffffff16565b91508061120981612155565b9150506111c8565b506000611240828d8d8151811061122a5761122a611c81565b60200260200101516116df90919063ffffffff16565b9050600061124d82611734565b9050600061125b858361146f565b9050600061126986836113d7565b905061129161128a6112838c670de0b6b3a7640000612181565b849061175e565b8290611360565b98505050505050505050979650505050505050565b60606000845167ffffffffffffffff8111156112c4576112c46119d2565b6040519080825280602002602001820160405280156112ed578160200160208202803683370190505b50905060005b8551811015611357576113328461132c8789858151811061131657611316611c81565b602002602001015161175e90919063ffffffff16565b906116df565b82828151811061134457611344611c81565b60209081029190910101526001016112f3565b50949350505050565b60008061136d838561216e565b905061115a848210156000611795565b60008061138a8385611ea0565b905061115a8415806113a45750836113a28684611eb7565b145b6003611795565b60006113ba8215156004611795565b61115a8284611eb7565b6113d4816210905360ea1b6117a7565b50565b60006113e7838311156001611795565b6000610b4e8385612181565b60006114028215156004611795565b8260000361141257506000610e9a565b6000611426670de0b6b3a764000085611ea0565b9050611446670de0b6b3a764000061143e8684611eb7565b146005611795565b82611452600183612181565b61145c9190611eb7565b61146790600161216e565b915050610e9a565b60008061147c8385611ea0565b90506114948415806113a45750836113a28684611eb7565b806000036114a6576000915050610e9a565b670de0b6b3a7640000611452600183612181565b6000808451866114ca9190611ea0565b90506000856000815181106114e1576114e1611c81565b60200260200101519050600086518760008151811061150257611502611c81565b60200260200101516115149190611ea0565b905060015b87518110156115835761155861155261154b848b858151811061153e5761153e611c81565b602002602001015161137d565b8a5161137d565b886113ab565b915061156f888281518110610ec657610ec6611c81565b92508061157b81612155565b915050611519565b5086858151811061159657611596611c81565b6020026020010151826115a99190612181565b915060006115b7878861137d565b905060006115ee6115dc6115d4846115cf898861137d565b61180a565b6103e861137d565b8a898151811061153e5761153e611c81565b905060006116096116026115d48b896113ab565b8690611360565b905060008061162561161b8686611360565b6115cf8d86611360565b905060005b60ff8110156116c35781925061166061164786610fa2858661137d565b6115cf8e61165a88610fa288600261137d565b906113d7565b9150828211156116905760016116768484612181565b1161168b57509750610b4e9650505050505050565b6116b1565b600161169c8385612181565b116116b157509750610b4e9650505050505050565b806116bb81612155565b91505061162a565b506116cf6101426113c4565b5050505050505050949350505050565b60006116ee8215156004611795565b826000036116fe57506000610e9a565b6000611712670de0b6b3a764000085611ea0565b905061172a670de0b6b3a764000061143e8684611eb7565b6114678382611eb7565b6000670de0b6b3a7640000821061174c576000610e9a565b610e9a82670de0b6b3a7640000612181565b60008061176b8385611ea0565b90506117838415806113a45750836113a28684611eb7565b610b4e670de0b6b3a764000082611eb7565b816117a3576117a3816113c4565b5050565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b60006118198215156004611795565b8260000361182957506000610e9a565b81611835600185612181565b61183f9190611eb7565b61184a90600161216e565b9050610e9a565b6001600160a01b03811681146113d457600080fd5b803561187181611851565b919050565b60008060008060008060c0878903121561188f57600080fd5b863561189a81611851565b955060208701356118aa81611851565b945060408701356118ba81611851565b9350606087013592506080870135915060a08701356118d881611851565b809150509295509295509295565b60008060008060008060c087890312156118ff57600080fd5b863561190a81611851565b95506020870135945060408701359350606087013561192881611851565b9250608087013561193881611851565b8092505060a087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561198557835183529284019291840191600101611969565b50909695505050505050565b6000806000606084860312156119a657600080fd5b83356119b181611851565b925060208401356119c181611851565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b60405290565b604051610160810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b604051601f8201601f1916810167ffffffffffffffff81118282101715611a5e57611a5e6119d2565b604052919050565b600060808284031215611a7857600080fd5b6040516080810181811067ffffffffffffffff82111715611a9b57611a9b6119d2565b6040529050808235611aac81611851565b81526020830135611abc81611851565b60208201526040830135611acf81611851565b60408201526060830135611ae281611851565b6060919091015292915050565b600060608284031215611b0157600080fd5b611b096119e8565b90508135611b1681611851565b81526020820135611b2681611851565b60208201526040820135611b3981611851565b604082015292915050565b600060608284031215611b5657600080fd5b611b5e6119e8565b905081358152602082013560208201526040820135604082015292915050565b60008060008385036102c0811215611b9557600080fd5b61028080821215611ba557600080fd5b611bad611a11565b9150611bb886611866565b8252611bc660208701611866565b6020830152611bd760408701611866565b6040830152606086013560608301526080860135608083015260a086013560a083015260c086013560c0830152611c118760e08801611a66565b60e0830152611c24876101608801611aef565b610100830152611c38876101c08801611aef565b610120830152611c4c876102208801611b44565b61014083015290969085013595506102a0909401359392505050565b600060208284031215611c7a57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8051801515811461187157600080fd5b60008060008060008060c08789031215611cc057600080fd5b8651611ccb81611851565b6020880151909650611cdc81611851565b6040880151909550611ced81611851565b6060880151909450611cfe81611851565b6080880151909350611d0f81611851565b9150611d1d60a08801611c97565b90509295509295509295565b600060208284031215611d3b57600080fd5b815161115a81611851565b600081518084526020808501945080840160005b83811015611d7f5781516001600160a01b031687529582019590820190600101611d5a565b509495945050505050565b60006101e0808352611d9e8184018a611d46565b90508281036020840152611db28189611d46565b90508281036040840152611dc68188611d46565b90508281036060840152611dda8187611d46565b91505083516080830152602084015160a0830152604084015160c0830152606084015160e0830152825115156101008301526020830151151561012083015260408301511515610140830152606083015115156101608301526080830151151561018083015260a0830151611e546101a084018215159052565b5060c08301518015156101c084015250979650505050505050565b600060208284031215611e8157600080fd5b61115a82611c97565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e9a57610e9a611e8a565b600082611ed457634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215611eec57600080fd5b505080516020909101519092909150565b600067ffffffffffffffff821115611f1757611f176119d2565b5060051b60200190565b600082601f830112611f3257600080fd5b81516020611f47611f4283611efd565b611a35565b82815260059290921b84018101918181019086841115611f6657600080fd5b8286015b84811015611f815780518352918301918301611f6a565b509695505050505050565b600080600060608486031215611fa157600080fd5b835167ffffffffffffffff80821115611fb957600080fd5b818601915086601f830112611fcd57600080fd5b81516020611fdd611f4283611efd565b82815260059290921b8401810191818101908a841115611ffc57600080fd5b948201945b8386101561202357855161201481611851565b82529482019490820190612001565b9189015191975090935050508082111561203c57600080fd5b5061204986828701611f21565b925050604084015190509250925092565b6000815180845260005b8181101561208057602081850181015186830182015201612064565b506000602082860101526020601f19601f83011685010191505092915050565b8481526000602060018060a01b03808716828501528086166040850152506080606084015283516080808501526120db610100850182611d46565b82860151607f19868303810160a0880152815180845291850193506000929091908501905b808410156121205784518252938501936001939093019290850190612100565b5060408801519450818782030160c088015261213c818661205a565b9450505050506060840151611f8160e085018215159052565b60006001820161216757612167611e8a565b5060010190565b80820180821115610e9a57610e9a611e8a565b81810381811115610e9a57610e9a611e8a56fea2646970667358221220be72fc31a30530bc2055ba244756e954d9071aa16d4baaaa040440b046d25eac64736f6c63430008130033

Deployed Bytecode

0x73969c65552b3e980b6566a7c68759e7bae8c0068d30146080604052600436106100565760003560e01c806308ed854f1461005b5780639bc9ed5714610088578063c2ceb95f146100a8578063f00449e9146100ca575b600080fd5b61006e610069366004611876565b6100ea565b604080519283526020830191909152015b60405180910390f35b61009b6100963660046118e6565b6101b4565b60405161007f919061194d565b8180156100b457600080fd5b506100c86100c3366004611991565b6101df565b005b8180156100d657600080fd5b506100c86100e5366004611b7e565b6104e2565b6040516370a0823160e01b8152306004820152600090819081906001600160a01b038816906370a0823190602401602060405180830381865afa158015610135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101599190611c68565b9050600061016b8588888d8d876101b4565b90508060008151811061018057610180611c81565b60200260200101518160018151811061019b5761019b611c81565b6020026020010151935093505050965096945050505050565b606060006101c58887878787610862565b90506101d388888784610a54565b98975050505050505050565b604051631526fe2760e01b8152600481018290526000906001600160a01b03851690631526fe279060240160c060405180830381865afa158015610227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024b9190611ca7565b505093505050506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190611c68565b905060008167ffffffffffffffff8111156102d3576102d36119d2565b6040519080825280602002602001820160405280156102fc578160200160208202803683370190505b50905060005b828110156103a557604051632061aa2360e11b8152600481018290526001600160a01b038516906340c3544690602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611d29565b82828151811061038557610385611c81565b6001600160a01b0390921660209283029190910190910152600101610302565b506040805160018082528183019092526000916020808301908036833701905050905083816000815181106103dc576103dc611c81565b6001600160a01b039283166020918202929092010152861663d34640b282846000604051908082528060200260200182016040528015610426578160200160208202803683370190505b5060408051600080825260a08083018452602080840183815284860184905260608086018590526080808701869052875160e08082018a52878252948101879052808901879052918201869052810185905292830184905260c083019390935293519388901b6001600160e01b03191684526104a796959493600401611d8a565b600060405180830381600087803b1580156104c157600080fd5b505af11580156104d5573d6000803e3d6000fd5b5050505050505050505050565b6101208301516040908101519051631c683a1b60e11b815260048101839052600060248201526001600160a01b03909116906338d07436906044016020604051808303816000875af115801561053c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105609190611e6f565b50610120830151516101408401516040908101519051630441a3e760e41b81526001600160a01b039092169163441a3e70916105a9918590600401918252602082015260400190565b6020604051808303816000875af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190611e6f565b50600061062284610100015160000151856101400151602001518661010001516020015187610100015160400151600019610862565b61010085015180516101408701516020908101519083015160409384015193516370a0823160e01b81523060048201529495506106d5949293919290916001600160a01b0316906370a0823190602401602060405180830381865afa15801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190611c68565b670de0b6b3a76400006106c68988611ea0565b6106d09190611eb7565b610b56565b6101008401518051610140860151516020909201516000926106fa9291600019610a54565b6040805160028082526060820183529293506000929091602083019080368337019050509050670de0b6b3a7640000858360008151811061073d5761073d611c81565b602002602001015161074f9190611ea0565b6107599190611eb7565b8160008151811061076c5761076c611c81565b602002602001018181525050670de0b6b3a7640000858360018151811061079557610795611c81565b60200260200101516107a79190611ea0565b6107b19190611eb7565b816001815181106107c4576107c4611c81565b60209081029190910181019190915261010087015180516101408901515191909201516040516370a0823160e01b815230600482015261085a9392916001600160a01b0316906370a0823190602401602060405180830381865afa158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190611c68565b84610d37565b505050505050565b600060001982036108d8576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d59190611c68565b91505b60006108e48787610e21565b90506000846001600160a01b0316639b02cdde6040518163ffffffff1660e01b81526004016040805180830381865afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109499190611ed9565b91505060006109588284610ea0565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611c68565b905060006109cd8b8b8b611056565b90506000886001600160a01b03166355c676286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a339190611c68565b9050610a448587848b878987611161565b9c9b505050505050505050505050565b60606000198203610aca576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190611c68565b91505b6000610ad68686610e21565b90506000846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3c9190611c68565b9050610b498285836112a6565b925050505b949350505050565b604051631f29a8cd60e31b8152600481018590526000906001600160a01b0387169063f94d466890602401600060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bc69190810190611f8c565b505090506000815167ffffffffffffffff811115610be657610be66119d2565b604051908082528060200260200182016040528015610c0f578160200160208202803683370190505b50905060005b8151811015610c7e57856001600160a01b0316838281518110610c3a57610c3a611c81565b60200260200101516001600160a01b031614610c57576000610c59565b835b828281518110610c6b57610c6b611c81565b6020908102919091010152600101610c15565b50604080516000602082018190529181018690526060810182905260800160408051601f1981840301815260808301825285835260208301859052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b038a1690638bdb391390610cfa908b903090819087906004016120a0565b600060405180830381600087803b158015610d1457600080fd5b505af1158015610d28573d6000803e3d6000fd5b50505050505050505050505050565b604051631f29a8cd60e31b8152600481018490526000906001600160a01b0386169063f94d466890602401600060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da79190810190611f8c565b5050604080516001602082015290810185905290915060009060600160408051601f1981840301815260808301825284835260208301869052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b03881690638bdb3913906104a79089903090819087906004016120a0565b604051631f29a8cd60e31b8152600481018290526060906000906001600160a01b0385169063f94d466890602401600060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e949190810190611f8c565b50925050505b92915050565b80516000908190815b81811015610ef157610edd858281518110610ec657610ec6611c81565b60200260200101518461136090919063ffffffff16565b925080610ee981612155565b915050610ea9565b5081600003610f0557600092505050610e9a565b60008281610f138489611ea0565b905060005b60ff81101561103f578260005b86811015610f7657610f62610f3a838761137d565b610f5d8c8481518110610f4f57610f4f611c81565b60200260200101518a61137d565b6113ab565b915080610f6e81612155565b915050610f25565b50839450610fdd610fae610fa8610f8d848a61137d565b610fa2610f9a888d61137d565b6103e86113ab565b90611360565b8661137d565b610f5d610fc5610fbf8a600161216e565b8561137d565b610fa2610f9a610fd76103e88a612181565b8a61137d565b93508484111561100c576001610ff38686612181565b116110075783975050505050505050610e9a565b61102c565b60016110188587612181565b1161102c5783975050505050505050610e9a565b508061103781612155565b915050610f18565b5061104b6101416113c4565b505050505092915050565b604051631f29a8cd60e31b81526004810183905260009081906001600160a01b0386169063f94d466890602401600060405180830381865afa1580156110a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c89190810190611f8c565b5050905060005b815181101561111b57836001600160a01b03168282815181106110f4576110f4611c81565b60200260200101516001600160a01b03160361111357915061115a9050565b6001016110cf565b5060405162461bcd60e51b815260206004820152600f60248201526e1a5b99195e081b9bdd08199bdd5b99608a1b604482015260640160405180910390fd5b9392505050565b6000806111828461117c87611176818b6113d7565b906113f3565b9061146f565b905060006111928a8a848b6114ba565b905060006111c2828b8b815181106111ac576111ac611c81565b60200260200101516113d790919063ffffffff16565b90506000805b8b51811015611211576111fd8c82815181106111e6576111e6611c81565b60200260200101518361136090919063ffffffff16565b91508061120981612155565b9150506111c8565b506000611240828d8d8151811061122a5761122a611c81565b60200260200101516116df90919063ffffffff16565b9050600061124d82611734565b9050600061125b858361146f565b9050600061126986836113d7565b905061129161128a6112838c670de0b6b3a7640000612181565b849061175e565b8290611360565b98505050505050505050979650505050505050565b60606000845167ffffffffffffffff8111156112c4576112c46119d2565b6040519080825280602002602001820160405280156112ed578160200160208202803683370190505b50905060005b8551811015611357576113328461132c8789858151811061131657611316611c81565b602002602001015161175e90919063ffffffff16565b906116df565b82828151811061134457611344611c81565b60209081029190910101526001016112f3565b50949350505050565b60008061136d838561216e565b905061115a848210156000611795565b60008061138a8385611ea0565b905061115a8415806113a45750836113a28684611eb7565b145b6003611795565b60006113ba8215156004611795565b61115a8284611eb7565b6113d4816210905360ea1b6117a7565b50565b60006113e7838311156001611795565b6000610b4e8385612181565b60006114028215156004611795565b8260000361141257506000610e9a565b6000611426670de0b6b3a764000085611ea0565b9050611446670de0b6b3a764000061143e8684611eb7565b146005611795565b82611452600183612181565b61145c9190611eb7565b61146790600161216e565b915050610e9a565b60008061147c8385611ea0565b90506114948415806113a45750836113a28684611eb7565b806000036114a6576000915050610e9a565b670de0b6b3a7640000611452600183612181565b6000808451866114ca9190611ea0565b90506000856000815181106114e1576114e1611c81565b60200260200101519050600086518760008151811061150257611502611c81565b60200260200101516115149190611ea0565b905060015b87518110156115835761155861155261154b848b858151811061153e5761153e611c81565b602002602001015161137d565b8a5161137d565b886113ab565b915061156f888281518110610ec657610ec6611c81565b92508061157b81612155565b915050611519565b5086858151811061159657611596611c81565b6020026020010151826115a99190612181565b915060006115b7878861137d565b905060006115ee6115dc6115d4846115cf898861137d565b61180a565b6103e861137d565b8a898151811061153e5761153e611c81565b905060006116096116026115d48b896113ab565b8690611360565b905060008061162561161b8686611360565b6115cf8d86611360565b905060005b60ff8110156116c35781925061166061164786610fa2858661137d565b6115cf8e61165a88610fa288600261137d565b906113d7565b9150828211156116905760016116768484612181565b1161168b57509750610b4e9650505050505050565b6116b1565b600161169c8385612181565b116116b157509750610b4e9650505050505050565b806116bb81612155565b91505061162a565b506116cf6101426113c4565b5050505050505050949350505050565b60006116ee8215156004611795565b826000036116fe57506000610e9a565b6000611712670de0b6b3a764000085611ea0565b905061172a670de0b6b3a764000061143e8684611eb7565b6114678382611eb7565b6000670de0b6b3a7640000821061174c576000610e9a565b610e9a82670de0b6b3a7640000612181565b60008061176b8385611ea0565b90506117838415806113a45750836113a28684611eb7565b610b4e670de0b6b3a764000082611eb7565b816117a3576117a3816113c4565b5050565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b60006118198215156004611795565b8260000361182957506000610e9a565b81611835600185612181565b61183f9190611eb7565b61184a90600161216e565b9050610e9a565b6001600160a01b03811681146113d457600080fd5b803561187181611851565b919050565b60008060008060008060c0878903121561188f57600080fd5b863561189a81611851565b955060208701356118aa81611851565b945060408701356118ba81611851565b9350606087013592506080870135915060a08701356118d881611851565b809150509295509295509295565b60008060008060008060c087890312156118ff57600080fd5b863561190a81611851565b95506020870135945060408701359350606087013561192881611851565b9250608087013561193881611851565b8092505060a087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561198557835183529284019291840191600101611969565b50909695505050505050565b6000806000606084860312156119a657600080fd5b83356119b181611851565b925060208401356119c181611851565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b60405290565b604051610160810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b604051601f8201601f1916810167ffffffffffffffff81118282101715611a5e57611a5e6119d2565b604052919050565b600060808284031215611a7857600080fd5b6040516080810181811067ffffffffffffffff82111715611a9b57611a9b6119d2565b6040529050808235611aac81611851565b81526020830135611abc81611851565b60208201526040830135611acf81611851565b60408201526060830135611ae281611851565b6060919091015292915050565b600060608284031215611b0157600080fd5b611b096119e8565b90508135611b1681611851565b81526020820135611b2681611851565b60208201526040820135611b3981611851565b604082015292915050565b600060608284031215611b5657600080fd5b611b5e6119e8565b905081358152602082013560208201526040820135604082015292915050565b60008060008385036102c0811215611b9557600080fd5b61028080821215611ba557600080fd5b611bad611a11565b9150611bb886611866565b8252611bc660208701611866565b6020830152611bd760408701611866565b6040830152606086013560608301526080860135608083015260a086013560a083015260c086013560c0830152611c118760e08801611a66565b60e0830152611c24876101608801611aef565b610100830152611c38876101c08801611aef565b610120830152611c4c876102208801611b44565b61014083015290969085013595506102a0909401359392505050565b600060208284031215611c7a57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8051801515811461187157600080fd5b60008060008060008060c08789031215611cc057600080fd5b8651611ccb81611851565b6020880151909650611cdc81611851565b6040880151909550611ced81611851565b6060880151909450611cfe81611851565b6080880151909350611d0f81611851565b9150611d1d60a08801611c97565b90509295509295509295565b600060208284031215611d3b57600080fd5b815161115a81611851565b600081518084526020808501945080840160005b83811015611d7f5781516001600160a01b031687529582019590820190600101611d5a565b509495945050505050565b60006101e0808352611d9e8184018a611d46565b90508281036020840152611db28189611d46565b90508281036040840152611dc68188611d46565b90508281036060840152611dda8187611d46565b91505083516080830152602084015160a0830152604084015160c0830152606084015160e0830152825115156101008301526020830151151561012083015260408301511515610140830152606083015115156101608301526080830151151561018083015260a0830151611e546101a084018215159052565b5060c08301518015156101c084015250979650505050505050565b600060208284031215611e8157600080fd5b61115a82611c97565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e9a57610e9a611e8a565b600082611ed457634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215611eec57600080fd5b505080516020909101519092909150565b600067ffffffffffffffff821115611f1757611f176119d2565b5060051b60200190565b600082601f830112611f3257600080fd5b81516020611f47611f4283611efd565b611a35565b82815260059290921b84018101918181019086841115611f6657600080fd5b8286015b84811015611f815780518352918301918301611f6a565b509695505050505050565b600080600060608486031215611fa157600080fd5b835167ffffffffffffffff80821115611fb957600080fd5b818601915086601f830112611fcd57600080fd5b81516020611fdd611f4283611efd565b82815260059290921b8401810191818101908a841115611ffc57600080fd5b948201945b8386101561202357855161201481611851565b82529482019490820190612001565b9189015191975090935050508082111561203c57600080fd5b5061204986828701611f21565b925050604084015190509250925092565b6000815180845260005b8181101561208057602081850181015186830182015201612064565b506000602082860101526020601f19601f83011685010191505092915050565b8481526000602060018060a01b03808716828501528086166040850152506080606084015283516080808501526120db610100850182611d46565b82860151607f19868303810160a0880152815180845291850193506000929091908501905b808410156121205784518252938501936001939093019290850190612100565b5060408801519450818782030160c088015261213c818661205a565b9450505050506060840151611f8160e085018215159052565b60006001820161216757612167611e8a565b5060010190565b80820180821115610e9a57610e9a611e8a565b81810381811115610e9a57610e9a611e8a56fea2646970667358221220be72fc31a30530bc2055ba244756e954d9071aa16d4baaaa040440b046d25eac64736f6c63430008130033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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