Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x6121ca61 | 18597055 | 331 days ago | IN | 0 ETH | 0.03641198 |
Loading...
Loading
Contract Name:
AuraLibPub
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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 ); } }
// 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); }
// 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); }
// 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)); } }
// 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); } } }
// 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); }
// 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; }
// 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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IStaker { function balanceOfPool(address _gauge) external view returns(uint256); }
// 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); }
// 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); }
// 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); } }
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]); }
// 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; }
// 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; } }
// 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; } }
// 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; } }
// 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; } } }
// 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); } }
// 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; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
6121ca61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806308ed854f1461005b5780639bc9ed5714610088578063c2ceb95f146100a8578063f00449e9146100ca575b600080fd5b61006e610069366004611876565b6100ea565b604080519283526020830191909152015b60405180910390f35b61009b6100963660046118e6565b6101b4565b60405161007f919061194d565b8180156100b457600080fd5b506100c86100c3366004611991565b6101df565b005b8180156100d657600080fd5b506100c86100e5366004611b7e565b6104e2565b6040516370a0823160e01b8152306004820152600090819081906001600160a01b038816906370a0823190602401602060405180830381865afa158015610135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101599190611c68565b9050600061016b8588888d8d876101b4565b90508060008151811061018057610180611c81565b60200260200101518160018151811061019b5761019b611c81565b6020026020010151935093505050965096945050505050565b606060006101c58887878787610862565b90506101d388888784610a54565b98975050505050505050565b604051631526fe2760e01b8152600481018290526000906001600160a01b03851690631526fe279060240160c060405180830381865afa158015610227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024b9190611ca7565b505093505050506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190611c68565b905060008167ffffffffffffffff8111156102d3576102d36119d2565b6040519080825280602002602001820160405280156102fc578160200160208202803683370190505b50905060005b828110156103a557604051632061aa2360e11b8152600481018290526001600160a01b038516906340c3544690602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611d29565b82828151811061038557610385611c81565b6001600160a01b0390921660209283029190910190910152600101610302565b506040805160018082528183019092526000916020808301908036833701905050905083816000815181106103dc576103dc611c81565b6001600160a01b039283166020918202929092010152861663d34640b282846000604051908082528060200260200182016040528015610426578160200160208202803683370190505b5060408051600080825260a08083018452602080840183815284860184905260608086018590526080808701869052875160e08082018a52878252948101879052808901879052918201869052810185905292830184905260c083019390935293519388901b6001600160e01b03191684526104a796959493600401611d8a565b600060405180830381600087803b1580156104c157600080fd5b505af11580156104d5573d6000803e3d6000fd5b5050505050505050505050565b6101208301516040908101519051631c683a1b60e11b815260048101839052600060248201526001600160a01b03909116906338d07436906044016020604051808303816000875af115801561053c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105609190611e6f565b50610120830151516101408401516040908101519051630441a3e760e41b81526001600160a01b039092169163441a3e70916105a9918590600401918252602082015260400190565b6020604051808303816000875af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190611e6f565b50600061062284610100015160000151856101400151602001518661010001516020015187610100015160400151600019610862565b61010085015180516101408701516020908101519083015160409384015193516370a0823160e01b81523060048201529495506106d5949293919290916001600160a01b0316906370a0823190602401602060405180830381865afa15801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190611c68565b670de0b6b3a76400006106c68988611ea0565b6106d09190611eb7565b610b56565b6101008401518051610140860151516020909201516000926106fa9291600019610a54565b6040805160028082526060820183529293506000929091602083019080368337019050509050670de0b6b3a7640000858360008151811061073d5761073d611c81565b602002602001015161074f9190611ea0565b6107599190611eb7565b8160008151811061076c5761076c611c81565b602002602001018181525050670de0b6b3a7640000858360018151811061079557610795611c81565b60200260200101516107a79190611ea0565b6107b19190611eb7565b816001815181106107c4576107c4611c81565b60209081029190910181019190915261010087015180516101408901515191909201516040516370a0823160e01b815230600482015261085a9392916001600160a01b0316906370a0823190602401602060405180830381865afa158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190611c68565b84610d37565b505050505050565b600060001982036108d8576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d59190611c68565b91505b60006108e48787610e21565b90506000846001600160a01b0316639b02cdde6040518163ffffffff1660e01b81526004016040805180830381865afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109499190611ed9565b91505060006109588284610ea0565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611c68565b905060006109cd8b8b8b611056565b90506000886001600160a01b03166355c676286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a339190611c68565b9050610a448587848b878987611161565b9c9b505050505050505050505050565b60606000198203610aca576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190611c68565b91505b6000610ad68686610e21565b90506000846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3c9190611c68565b9050610b498285836112a6565b925050505b949350505050565b604051631f29a8cd60e31b8152600481018590526000906001600160a01b0387169063f94d466890602401600060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bc69190810190611f8c565b505090506000815167ffffffffffffffff811115610be657610be66119d2565b604051908082528060200260200182016040528015610c0f578160200160208202803683370190505b50905060005b8151811015610c7e57856001600160a01b0316838281518110610c3a57610c3a611c81565b60200260200101516001600160a01b031614610c57576000610c59565b835b828281518110610c6b57610c6b611c81565b6020908102919091010152600101610c15565b50604080516000602082018190529181018690526060810182905260800160408051601f1981840301815260808301825285835260208301859052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b038a1690638bdb391390610cfa908b903090819087906004016120a0565b600060405180830381600087803b158015610d1457600080fd5b505af1158015610d28573d6000803e3d6000fd5b50505050505050505050505050565b604051631f29a8cd60e31b8152600481018490526000906001600160a01b0386169063f94d466890602401600060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da79190810190611f8c565b5050604080516001602082015290810185905290915060009060600160408051601f1981840301815260808301825284835260208301869052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b03881690638bdb3913906104a79089903090819087906004016120a0565b604051631f29a8cd60e31b8152600481018290526060906000906001600160a01b0385169063f94d466890602401600060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e949190810190611f8c565b50925050505b92915050565b80516000908190815b81811015610ef157610edd858281518110610ec657610ec6611c81565b60200260200101518461136090919063ffffffff16565b925080610ee981612155565b915050610ea9565b5081600003610f0557600092505050610e9a565b60008281610f138489611ea0565b905060005b60ff81101561103f578260005b86811015610f7657610f62610f3a838761137d565b610f5d8c8481518110610f4f57610f4f611c81565b60200260200101518a61137d565b6113ab565b915080610f6e81612155565b915050610f25565b50839450610fdd610fae610fa8610f8d848a61137d565b610fa2610f9a888d61137d565b6103e86113ab565b90611360565b8661137d565b610f5d610fc5610fbf8a600161216e565b8561137d565b610fa2610f9a610fd76103e88a612181565b8a61137d565b93508484111561100c576001610ff38686612181565b116110075783975050505050505050610e9a565b61102c565b60016110188587612181565b1161102c5783975050505050505050610e9a565b508061103781612155565b915050610f18565b5061104b6101416113c4565b505050505092915050565b604051631f29a8cd60e31b81526004810183905260009081906001600160a01b0386169063f94d466890602401600060405180830381865afa1580156110a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c89190810190611f8c565b5050905060005b815181101561111b57836001600160a01b03168282815181106110f4576110f4611c81565b60200260200101516001600160a01b03160361111357915061115a9050565b6001016110cf565b5060405162461bcd60e51b815260206004820152600f60248201526e1a5b99195e081b9bdd08199bdd5b99608a1b604482015260640160405180910390fd5b9392505050565b6000806111828461117c87611176818b6113d7565b906113f3565b9061146f565b905060006111928a8a848b6114ba565b905060006111c2828b8b815181106111ac576111ac611c81565b60200260200101516113d790919063ffffffff16565b90506000805b8b51811015611211576111fd8c82815181106111e6576111e6611c81565b60200260200101518361136090919063ffffffff16565b91508061120981612155565b9150506111c8565b506000611240828d8d8151811061122a5761122a611c81565b60200260200101516116df90919063ffffffff16565b9050600061124d82611734565b9050600061125b858361146f565b9050600061126986836113d7565b905061129161128a6112838c670de0b6b3a7640000612181565b849061175e565b8290611360565b98505050505050505050979650505050505050565b60606000845167ffffffffffffffff8111156112c4576112c46119d2565b6040519080825280602002602001820160405280156112ed578160200160208202803683370190505b50905060005b8551811015611357576113328461132c8789858151811061131657611316611c81565b602002602001015161175e90919063ffffffff16565b906116df565b82828151811061134457611344611c81565b60209081029190910101526001016112f3565b50949350505050565b60008061136d838561216e565b905061115a848210156000611795565b60008061138a8385611ea0565b905061115a8415806113a45750836113a28684611eb7565b145b6003611795565b60006113ba8215156004611795565b61115a8284611eb7565b6113d4816210905360ea1b6117a7565b50565b60006113e7838311156001611795565b6000610b4e8385612181565b60006114028215156004611795565b8260000361141257506000610e9a565b6000611426670de0b6b3a764000085611ea0565b9050611446670de0b6b3a764000061143e8684611eb7565b146005611795565b82611452600183612181565b61145c9190611eb7565b61146790600161216e565b915050610e9a565b60008061147c8385611ea0565b90506114948415806113a45750836113a28684611eb7565b806000036114a6576000915050610e9a565b670de0b6b3a7640000611452600183612181565b6000808451866114ca9190611ea0565b90506000856000815181106114e1576114e1611c81565b60200260200101519050600086518760008151811061150257611502611c81565b60200260200101516115149190611ea0565b905060015b87518110156115835761155861155261154b848b858151811061153e5761153e611c81565b602002602001015161137d565b8a5161137d565b886113ab565b915061156f888281518110610ec657610ec6611c81565b92508061157b81612155565b915050611519565b5086858151811061159657611596611c81565b6020026020010151826115a99190612181565b915060006115b7878861137d565b905060006115ee6115dc6115d4846115cf898861137d565b61180a565b6103e861137d565b8a898151811061153e5761153e611c81565b905060006116096116026115d48b896113ab565b8690611360565b905060008061162561161b8686611360565b6115cf8d86611360565b905060005b60ff8110156116c35781925061166061164786610fa2858661137d565b6115cf8e61165a88610fa288600261137d565b906113d7565b9150828211156116905760016116768484612181565b1161168b57509750610b4e9650505050505050565b6116b1565b600161169c8385612181565b116116b157509750610b4e9650505050505050565b806116bb81612155565b91505061162a565b506116cf6101426113c4565b5050505050505050949350505050565b60006116ee8215156004611795565b826000036116fe57506000610e9a565b6000611712670de0b6b3a764000085611ea0565b905061172a670de0b6b3a764000061143e8684611eb7565b6114678382611eb7565b6000670de0b6b3a7640000821061174c576000610e9a565b610e9a82670de0b6b3a7640000612181565b60008061176b8385611ea0565b90506117838415806113a45750836113a28684611eb7565b610b4e670de0b6b3a764000082611eb7565b816117a3576117a3816113c4565b5050565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b60006118198215156004611795565b8260000361182957506000610e9a565b81611835600185612181565b61183f9190611eb7565b61184a90600161216e565b9050610e9a565b6001600160a01b03811681146113d457600080fd5b803561187181611851565b919050565b60008060008060008060c0878903121561188f57600080fd5b863561189a81611851565b955060208701356118aa81611851565b945060408701356118ba81611851565b9350606087013592506080870135915060a08701356118d881611851565b809150509295509295509295565b60008060008060008060c087890312156118ff57600080fd5b863561190a81611851565b95506020870135945060408701359350606087013561192881611851565b9250608087013561193881611851565b8092505060a087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561198557835183529284019291840191600101611969565b50909695505050505050565b6000806000606084860312156119a657600080fd5b83356119b181611851565b925060208401356119c181611851565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b60405290565b604051610160810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b604051601f8201601f1916810167ffffffffffffffff81118282101715611a5e57611a5e6119d2565b604052919050565b600060808284031215611a7857600080fd5b6040516080810181811067ffffffffffffffff82111715611a9b57611a9b6119d2565b6040529050808235611aac81611851565b81526020830135611abc81611851565b60208201526040830135611acf81611851565b60408201526060830135611ae281611851565b6060919091015292915050565b600060608284031215611b0157600080fd5b611b096119e8565b90508135611b1681611851565b81526020820135611b2681611851565b60208201526040820135611b3981611851565b604082015292915050565b600060608284031215611b5657600080fd5b611b5e6119e8565b905081358152602082013560208201526040820135604082015292915050565b60008060008385036102c0811215611b9557600080fd5b61028080821215611ba557600080fd5b611bad611a11565b9150611bb886611866565b8252611bc660208701611866565b6020830152611bd760408701611866565b6040830152606086013560608301526080860135608083015260a086013560a083015260c086013560c0830152611c118760e08801611a66565b60e0830152611c24876101608801611aef565b610100830152611c38876101c08801611aef565b610120830152611c4c876102208801611b44565b61014083015290969085013595506102a0909401359392505050565b600060208284031215611c7a57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8051801515811461187157600080fd5b60008060008060008060c08789031215611cc057600080fd5b8651611ccb81611851565b6020880151909650611cdc81611851565b6040880151909550611ced81611851565b6060880151909450611cfe81611851565b6080880151909350611d0f81611851565b9150611d1d60a08801611c97565b90509295509295509295565b600060208284031215611d3b57600080fd5b815161115a81611851565b600081518084526020808501945080840160005b83811015611d7f5781516001600160a01b031687529582019590820190600101611d5a565b509495945050505050565b60006101e0808352611d9e8184018a611d46565b90508281036020840152611db28189611d46565b90508281036040840152611dc68188611d46565b90508281036060840152611dda8187611d46565b91505083516080830152602084015160a0830152604084015160c0830152606084015160e0830152825115156101008301526020830151151561012083015260408301511515610140830152606083015115156101608301526080830151151561018083015260a0830151611e546101a084018215159052565b5060c08301518015156101c084015250979650505050505050565b600060208284031215611e8157600080fd5b61115a82611c97565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e9a57610e9a611e8a565b600082611ed457634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215611eec57600080fd5b505080516020909101519092909150565b600067ffffffffffffffff821115611f1757611f176119d2565b5060051b60200190565b600082601f830112611f3257600080fd5b81516020611f47611f4283611efd565b611a35565b82815260059290921b84018101918181019086841115611f6657600080fd5b8286015b84811015611f815780518352918301918301611f6a565b509695505050505050565b600080600060608486031215611fa157600080fd5b835167ffffffffffffffff80821115611fb957600080fd5b818601915086601f830112611fcd57600080fd5b81516020611fdd611f4283611efd565b82815260059290921b8401810191818101908a841115611ffc57600080fd5b948201945b8386101561202357855161201481611851565b82529482019490820190612001565b9189015191975090935050508082111561203c57600080fd5b5061204986828701611f21565b925050604084015190509250925092565b6000815180845260005b8181101561208057602081850181015186830182015201612064565b506000602082860101526020601f19601f83011685010191505092915050565b8481526000602060018060a01b03808716828501528086166040850152506080606084015283516080808501526120db610100850182611d46565b82860151607f19868303810160a0880152815180845291850193506000929091908501905b808410156121205784518252938501936001939093019290850190612100565b5060408801519450818782030160c088015261213c818661205a565b9450505050506060840151611f8160e085018215159052565b60006001820161216757612167611e8a565b5060010190565b80820180821115610e9a57610e9a611e8a565b81810381811115610e9a57610e9a611e8a56fea2646970667358221220be72fc31a30530bc2055ba244756e954d9071aa16d4baaaa040440b046d25eac64736f6c63430008130033
Deployed Bytecode
0x73969c65552b3e980b6566a7c68759e7bae8c0068d30146080604052600436106100565760003560e01c806308ed854f1461005b5780639bc9ed5714610088578063c2ceb95f146100a8578063f00449e9146100ca575b600080fd5b61006e610069366004611876565b6100ea565b604080519283526020830191909152015b60405180910390f35b61009b6100963660046118e6565b6101b4565b60405161007f919061194d565b8180156100b457600080fd5b506100c86100c3366004611991565b6101df565b005b8180156100d657600080fd5b506100c86100e5366004611b7e565b6104e2565b6040516370a0823160e01b8152306004820152600090819081906001600160a01b038816906370a0823190602401602060405180830381865afa158015610135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101599190611c68565b9050600061016b8588888d8d876101b4565b90508060008151811061018057610180611c81565b60200260200101518160018151811061019b5761019b611c81565b6020026020010151935093505050965096945050505050565b606060006101c58887878787610862565b90506101d388888784610a54565b98975050505050505050565b604051631526fe2760e01b8152600481018290526000906001600160a01b03851690631526fe279060240160c060405180830381865afa158015610227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024b9190611ca7565b505093505050506000816001600160a01b031663d55a23f46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190611c68565b905060008167ffffffffffffffff8111156102d3576102d36119d2565b6040519080825280602002602001820160405280156102fc578160200160208202803683370190505b50905060005b828110156103a557604051632061aa2360e11b8152600481018290526001600160a01b038516906340c3544690602401602060405180830381865afa15801561034f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103739190611d29565b82828151811061038557610385611c81565b6001600160a01b0390921660209283029190910190910152600101610302565b506040805160018082528183019092526000916020808301908036833701905050905083816000815181106103dc576103dc611c81565b6001600160a01b039283166020918202929092010152861663d34640b282846000604051908082528060200260200182016040528015610426578160200160208202803683370190505b5060408051600080825260a08083018452602080840183815284860184905260608086018590526080808701869052875160e08082018a52878252948101879052808901879052918201869052810185905292830184905260c083019390935293519388901b6001600160e01b03191684526104a796959493600401611d8a565b600060405180830381600087803b1580156104c157600080fd5b505af11580156104d5573d6000803e3d6000fd5b5050505050505050505050565b6101208301516040908101519051631c683a1b60e11b815260048101839052600060248201526001600160a01b03909116906338d07436906044016020604051808303816000875af115801561053c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105609190611e6f565b50610120830151516101408401516040908101519051630441a3e760e41b81526001600160a01b039092169163441a3e70916105a9918590600401918252602082015260400190565b6020604051808303816000875af11580156105c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ec9190611e6f565b50600061062284610100015160000151856101400151602001518661010001516020015187610100015160400151600019610862565b61010085015180516101408701516020908101519083015160409384015193516370a0823160e01b81523060048201529495506106d5949293919290916001600160a01b0316906370a0823190602401602060405180830381865afa15801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190611c68565b670de0b6b3a76400006106c68988611ea0565b6106d09190611eb7565b610b56565b6101008401518051610140860151516020909201516000926106fa9291600019610a54565b6040805160028082526060820183529293506000929091602083019080368337019050509050670de0b6b3a7640000858360008151811061073d5761073d611c81565b602002602001015161074f9190611ea0565b6107599190611eb7565b8160008151811061076c5761076c611c81565b602002602001018181525050670de0b6b3a7640000858360018151811061079557610795611c81565b60200260200101516107a79190611ea0565b6107b19190611eb7565b816001815181106107c4576107c4611c81565b60209081029190910181019190915261010087015180516101408901515191909201516040516370a0823160e01b815230600482015261085a9392916001600160a01b0316906370a0823190602401602060405180830381865afa158015610830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108549190611c68565b84610d37565b505050505050565b600060001982036108d8576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d59190611c68565b91505b60006108e48787610e21565b90506000846001600160a01b0316639b02cdde6040518163ffffffff1660e01b81526004016040805180830381865afa158015610925573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109499190611ed9565b91505060006109588284610ea0565b90506000866001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561099a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109be9190611c68565b905060006109cd8b8b8b611056565b90506000886001600160a01b03166355c676286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a339190611c68565b9050610a448587848b878987611161565b9c9b505050505050505050505050565b60606000198203610aca576040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac79190611c68565b91505b6000610ad68686610e21565b90506000846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3c9190611c68565b9050610b498285836112a6565b925050505b949350505050565b604051631f29a8cd60e31b8152600481018590526000906001600160a01b0387169063f94d466890602401600060405180830381865afa158015610b9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bc69190810190611f8c565b505090506000815167ffffffffffffffff811115610be657610be66119d2565b604051908082528060200260200182016040528015610c0f578160200160208202803683370190505b50905060005b8151811015610c7e57856001600160a01b0316838281518110610c3a57610c3a611c81565b60200260200101516001600160a01b031614610c57576000610c59565b835b828281518110610c6b57610c6b611c81565b6020908102919091010152600101610c15565b50604080516000602082018190529181018690526060810182905260800160408051601f1981840301815260808301825285835260208301859052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b038a1690638bdb391390610cfa908b903090819087906004016120a0565b600060405180830381600087803b158015610d1457600080fd5b505af1158015610d28573d6000803e3d6000fd5b50505050505050505050505050565b604051631f29a8cd60e31b8152600481018490526000906001600160a01b0386169063f94d466890602401600060405180830381865afa158015610d7f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da79190810190611f8c565b5050604080516001602082015290810185905290915060009060600160408051601f1981840301815260808301825284835260208301869052828201819052600060608401529051638bdb391360e01b81529092506001600160a01b03881690638bdb3913906104a79089903090819087906004016120a0565b604051631f29a8cd60e31b8152600481018290526060906000906001600160a01b0385169063f94d466890602401600060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e949190810190611f8c565b50925050505b92915050565b80516000908190815b81811015610ef157610edd858281518110610ec657610ec6611c81565b60200260200101518461136090919063ffffffff16565b925080610ee981612155565b915050610ea9565b5081600003610f0557600092505050610e9a565b60008281610f138489611ea0565b905060005b60ff81101561103f578260005b86811015610f7657610f62610f3a838761137d565b610f5d8c8481518110610f4f57610f4f611c81565b60200260200101518a61137d565b6113ab565b915080610f6e81612155565b915050610f25565b50839450610fdd610fae610fa8610f8d848a61137d565b610fa2610f9a888d61137d565b6103e86113ab565b90611360565b8661137d565b610f5d610fc5610fbf8a600161216e565b8561137d565b610fa2610f9a610fd76103e88a612181565b8a61137d565b93508484111561100c576001610ff38686612181565b116110075783975050505050505050610e9a565b61102c565b60016110188587612181565b1161102c5783975050505050505050610e9a565b508061103781612155565b915050610f18565b5061104b6101416113c4565b505050505092915050565b604051631f29a8cd60e31b81526004810183905260009081906001600160a01b0386169063f94d466890602401600060405180830381865afa1580156110a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110c89190810190611f8c565b5050905060005b815181101561111b57836001600160a01b03168282815181106110f4576110f4611c81565b60200260200101516001600160a01b03160361111357915061115a9050565b6001016110cf565b5060405162461bcd60e51b815260206004820152600f60248201526e1a5b99195e081b9bdd08199bdd5b99608a1b604482015260640160405180910390fd5b9392505050565b6000806111828461117c87611176818b6113d7565b906113f3565b9061146f565b905060006111928a8a848b6114ba565b905060006111c2828b8b815181106111ac576111ac611c81565b60200260200101516113d790919063ffffffff16565b90506000805b8b51811015611211576111fd8c82815181106111e6576111e6611c81565b60200260200101518361136090919063ffffffff16565b91508061120981612155565b9150506111c8565b506000611240828d8d8151811061122a5761122a611c81565b60200260200101516116df90919063ffffffff16565b9050600061124d82611734565b9050600061125b858361146f565b9050600061126986836113d7565b905061129161128a6112838c670de0b6b3a7640000612181565b849061175e565b8290611360565b98505050505050505050979650505050505050565b60606000845167ffffffffffffffff8111156112c4576112c46119d2565b6040519080825280602002602001820160405280156112ed578160200160208202803683370190505b50905060005b8551811015611357576113328461132c8789858151811061131657611316611c81565b602002602001015161175e90919063ffffffff16565b906116df565b82828151811061134457611344611c81565b60209081029190910101526001016112f3565b50949350505050565b60008061136d838561216e565b905061115a848210156000611795565b60008061138a8385611ea0565b905061115a8415806113a45750836113a28684611eb7565b145b6003611795565b60006113ba8215156004611795565b61115a8284611eb7565b6113d4816210905360ea1b6117a7565b50565b60006113e7838311156001611795565b6000610b4e8385612181565b60006114028215156004611795565b8260000361141257506000610e9a565b6000611426670de0b6b3a764000085611ea0565b9050611446670de0b6b3a764000061143e8684611eb7565b146005611795565b82611452600183612181565b61145c9190611eb7565b61146790600161216e565b915050610e9a565b60008061147c8385611ea0565b90506114948415806113a45750836113a28684611eb7565b806000036114a6576000915050610e9a565b670de0b6b3a7640000611452600183612181565b6000808451866114ca9190611ea0565b90506000856000815181106114e1576114e1611c81565b60200260200101519050600086518760008151811061150257611502611c81565b60200260200101516115149190611ea0565b905060015b87518110156115835761155861155261154b848b858151811061153e5761153e611c81565b602002602001015161137d565b8a5161137d565b886113ab565b915061156f888281518110610ec657610ec6611c81565b92508061157b81612155565b915050611519565b5086858151811061159657611596611c81565b6020026020010151826115a99190612181565b915060006115b7878861137d565b905060006115ee6115dc6115d4846115cf898861137d565b61180a565b6103e861137d565b8a898151811061153e5761153e611c81565b905060006116096116026115d48b896113ab565b8690611360565b905060008061162561161b8686611360565b6115cf8d86611360565b905060005b60ff8110156116c35781925061166061164786610fa2858661137d565b6115cf8e61165a88610fa288600261137d565b906113d7565b9150828211156116905760016116768484612181565b1161168b57509750610b4e9650505050505050565b6116b1565b600161169c8385612181565b116116b157509750610b4e9650505050505050565b806116bb81612155565b91505061162a565b506116cf6101426113c4565b5050505050505050949350505050565b60006116ee8215156004611795565b826000036116fe57506000610e9a565b6000611712670de0b6b3a764000085611ea0565b905061172a670de0b6b3a764000061143e8684611eb7565b6114678382611eb7565b6000670de0b6b3a7640000821061174c576000610e9a565b610e9a82670de0b6b3a7640000612181565b60008061176b8385611ea0565b90506117838415806113a45750836113a28684611eb7565b610b4e670de0b6b3a764000082611eb7565b816117a3576117a3816113c4565b5050565b62461bcd60e51b600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b604481905260e883901c91606490fd5b60006118198215156004611795565b8260000361182957506000610e9a565b81611835600185612181565b61183f9190611eb7565b61184a90600161216e565b9050610e9a565b6001600160a01b03811681146113d457600080fd5b803561187181611851565b919050565b60008060008060008060c0878903121561188f57600080fd5b863561189a81611851565b955060208701356118aa81611851565b945060408701356118ba81611851565b9350606087013592506080870135915060a08701356118d881611851565b809150509295509295509295565b60008060008060008060c087890312156118ff57600080fd5b863561190a81611851565b95506020870135945060408701359350606087013561192881611851565b9250608087013561193881611851565b8092505060a087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561198557835183529284019291840191600101611969565b50909695505050505050565b6000806000606084860312156119a657600080fd5b83356119b181611851565b925060208401356119c181611851565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b60405290565b604051610160810167ffffffffffffffff81118282101715611a0b57611a0b6119d2565b604051601f8201601f1916810167ffffffffffffffff81118282101715611a5e57611a5e6119d2565b604052919050565b600060808284031215611a7857600080fd5b6040516080810181811067ffffffffffffffff82111715611a9b57611a9b6119d2565b6040529050808235611aac81611851565b81526020830135611abc81611851565b60208201526040830135611acf81611851565b60408201526060830135611ae281611851565b6060919091015292915050565b600060608284031215611b0157600080fd5b611b096119e8565b90508135611b1681611851565b81526020820135611b2681611851565b60208201526040820135611b3981611851565b604082015292915050565b600060608284031215611b5657600080fd5b611b5e6119e8565b905081358152602082013560208201526040820135604082015292915050565b60008060008385036102c0811215611b9557600080fd5b61028080821215611ba557600080fd5b611bad611a11565b9150611bb886611866565b8252611bc660208701611866565b6020830152611bd760408701611866565b6040830152606086013560608301526080860135608083015260a086013560a083015260c086013560c0830152611c118760e08801611a66565b60e0830152611c24876101608801611aef565b610100830152611c38876101c08801611aef565b610120830152611c4c876102208801611b44565b61014083015290969085013595506102a0909401359392505050565b600060208284031215611c7a57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8051801515811461187157600080fd5b60008060008060008060c08789031215611cc057600080fd5b8651611ccb81611851565b6020880151909650611cdc81611851565b6040880151909550611ced81611851565b6060880151909450611cfe81611851565b6080880151909350611d0f81611851565b9150611d1d60a08801611c97565b90509295509295509295565b600060208284031215611d3b57600080fd5b815161115a81611851565b600081518084526020808501945080840160005b83811015611d7f5781516001600160a01b031687529582019590820190600101611d5a565b509495945050505050565b60006101e0808352611d9e8184018a611d46565b90508281036020840152611db28189611d46565b90508281036040840152611dc68188611d46565b90508281036060840152611dda8187611d46565b91505083516080830152602084015160a0830152604084015160c0830152606084015160e0830152825115156101008301526020830151151561012083015260408301511515610140830152606083015115156101608301526080830151151561018083015260a0830151611e546101a084018215159052565b5060c08301518015156101c084015250979650505050505050565b600060208284031215611e8157600080fd5b61115a82611c97565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e9a57610e9a611e8a565b600082611ed457634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215611eec57600080fd5b505080516020909101519092909150565b600067ffffffffffffffff821115611f1757611f176119d2565b5060051b60200190565b600082601f830112611f3257600080fd5b81516020611f47611f4283611efd565b611a35565b82815260059290921b84018101918181019086841115611f6657600080fd5b8286015b84811015611f815780518352918301918301611f6a565b509695505050505050565b600080600060608486031215611fa157600080fd5b835167ffffffffffffffff80821115611fb957600080fd5b818601915086601f830112611fcd57600080fd5b81516020611fdd611f4283611efd565b82815260059290921b8401810191818101908a841115611ffc57600080fd5b948201945b8386101561202357855161201481611851565b82529482019490820190612001565b9189015191975090935050508082111561203c57600080fd5b5061204986828701611f21565b925050604084015190509250925092565b6000815180845260005b8181101561208057602081850181015186830182015201612064565b506000602082860101526020601f19601f83011685010191505092915050565b8481526000602060018060a01b03808716828501528086166040850152506080606084015283516080808501526120db610100850182611d46565b82860151607f19868303810160a0880152815180845291850193506000929091908501905b808410156121205784518252938501936001939093019290850190612100565b5060408801519450818782030160c088015261213c818661205a565b9450505050506060840151611f8160e085018215159052565b60006001820161216757612167611e8a565b5060010190565b80820180821115610e9a57610e9a611e8a565b81810381811115610e9a57610e9a611e8a56fea2646970667358221220be72fc31a30530bc2055ba244756e954d9071aa16d4baaaa040440b046d25eac64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.