Polygon Sponsored slots available. Book your slot here!
More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
BalancerAMM
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: BUSL-1.1 pragma solidity 0.8.19; // ========================================================== // ====================== BalancerAMM.sol ==================== // ========================================================== /** * @title Balancer AMM * @dev Interactions with Balancer Pool */ import { ChainlinkLibrary, IPriceFeed } from "../Libraries/Chainlink.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; import { TransferHelper } from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; import { ISweep } from "../Sweep/ISweep.sol"; import { IAsset, SingleSwap, FundManagement, SwapKind, IBalancerVault, IBalancerPool } from "../Assets/Interfaces/Balancer/IBalancer.sol"; import { StableMath } from "../Libraries/Balancer/StableMath.sol"; import { IMarketMaker } from "../Balancer/IMarketMaker.sol"; contract BalancerAMM { using Math for uint256; IBalancerVault public vault; IBalancerPool public pool; IERC20Metadata public immutable base; ISweep public immutable sweep; IPriceFeed public immutable oracleBase; IPriceFeed public immutable sequencer; uint256 public immutable oracleBaseUpdateFrequency; IMarketMaker public marketMaker; uint8 private constant USD_DECIMALS = 6; uint16 private constant DEADLINE_GAP = 15 minutes; constructor( address _sweep, address _base, address _sequencer, address _oracleBase, uint256 _oracleBaseUpdateFrequency ) { sweep = ISweep(_sweep); base = IERC20Metadata(_base); oracleBase = IPriceFeed(_oracleBase); sequencer = IPriceFeed(_sequencer); oracleBaseUpdateFrequency = _oracleBaseUpdateFrequency; } // Events event Bought(uint256 usdxAmount); event Sold(uint256 sweepAmount); // Errors error ZeroAmount(); error BadRate(); error NotOwnerOrGov(); modifier onlyOwner () { if (msg.sender != sweep.fastMultisig() && msg.sender != sweep.owner()) revert NotOwnerOrGov(); _; } /** * @notice Get Price * @dev Get the quote for selling 1 unit of a token. */ function getPrice() public view returns (uint256 amountOut) { if(address(pool) == address(0)) return 2e6; uint8 sweepDecimals = sweep.decimals(); uint8 baseDecimals = base.decimals(); uint8 quoteDecimals = sweepDecimals - baseDecimals; uint256[] memory factors = pool.getScalingFactors(); (uint256 amplification, , ) = pool.getAmplificationParameter(); (IAsset[] memory tokens, uint256[] memory balances,) = IBalancerVault(pool.getVault()).getPoolTokens(pool.getPoolId()); uint8 tokenIndexIn = findAssetIndex(address(sweep), tokens); uint8 tokenIndexOut = findAssetIndex(address(base), tokens); uint256[] memory newBalances = new uint256[](2); newBalances[0] = balances[tokenIndexIn]; newBalances[1] = balances[tokenIndexOut] * (10 ** quoteDecimals); uint256 invariant = StableMath._calculateInvariant(amplification, newBalances); uint256 quote = StableMath._calcOutGivenIn(amplification, newBalances, 0, 1, 1e18, invariant); uint8 oracleDecimals = ChainlinkLibrary.getDecimals(oracleBase); uint256 price = ChainlinkLibrary.getPrice( oracleBase, sequencer, oracleBaseUpdateFrequency ); amountOut = (quote * factors[tokenIndexIn] * price) / (10 ** (oracleDecimals + sweepDecimals + quoteDecimals)); } /** * @notice Get TWA Price * @dev Get the quote for selling 1 unit of a token. */ function getTWAPrice() external view returns (uint256 amountOut) { return getPrice(); } function getRate() public view returns (uint256 rate) { rate = sweep.targetPrice() * 1e12; } function getPositions(uint256) public view returns (uint256 usdxAmount, uint256 sweepAmount, uint256 lp) { (IAsset[] memory tokens, uint256[] memory balances,) = IBalancerVault(pool.getVault()).getPoolTokens(pool.getPoolId()); uint8 usdxIndex = findAssetIndex(address(base), tokens); uint8 sweepIndex = findAssetIndex(address(sweep), tokens); uint8 lpIndex = findAssetIndex(address(pool), tokens); usdxAmount = balances[usdxIndex]; sweepAmount = balances[sweepIndex]; lp = balances[lpIndex]; } /* ========== Actions ========== */ /** * @notice Buy Sweep * @param usdxAddress Token Address to use for buying sweep. * @param usdxAmount Token Amount. * @param amountOutMin Minimum amount out. * @dev Increases the sweep balance and decrease collateral balance. */ function buySweep(address usdxAddress, uint256 usdxAmount, uint256 amountOutMin) external returns (uint256 sweepAmount) { emit Bought(usdxAmount); if (address(marketMaker) != address(0) && marketMaker.getBuyPrice() < getPrice()) { TransferHelper.safeTransferFrom(address(base), msg.sender, address(this), usdxAmount); TransferHelper.safeApprove(address(base), address(marketMaker), usdxAmount); sweepAmount = marketMaker.buySweep(usdxAmount); TransferHelper.safeTransfer(address(sweep), msg.sender, sweepAmount); } else { checkRate(usdxAddress, usdxAmount, amountOutMin); sweepAmount = swap(usdxAddress, address(sweep), usdxAmount, amountOutMin, address(pool)); } } /** * @notice Sell Sweep * @param usdxAddress Token Address to return after selling sweep. * @param sweepAmount Sweep Amount. * @param amountOutMin Minimum amount out. * @dev Decreases the sweep balance and increase collateral balance */ function sellSweep( address usdxAddress, uint256 sweepAmount, uint256 amountOutMin ) external returns (uint256 tokenAmount) { emit Sold(sweepAmount); checkRate(usdxAddress, amountOutMin, sweepAmount); tokenAmount = swap(address(sweep), usdxAddress, sweepAmount, amountOutMin, address(pool)); } /** * @notice Swap tokenIn for tokenOut using balancer exact input swap * @param tokenIn Address to in * @param tokenOut Address to out * @param amountIn Amount of _tokenA * @param amountOutMin Minimum amount out. */ function swapExactInput( address tokenIn, address tokenOut, uint24, uint256 amountIn, uint256 amountOutMin ) public returns (uint256 amountOut) { return swap(tokenIn, tokenOut, amountIn, amountOutMin, address(pool)); } function setPool(address poolAddress) external { require(msg.sender == sweep.owner(), "BalancerAMM: Not Governance"); pool = IBalancerPool(poolAddress); } function findAssetIndex(address asset, IAsset[] memory assets) internal pure returns (uint8) { for (uint8 i = 0; i < assets.length; i++) { if (address(assets[i]) == asset) { return i; } } revert("BalancerAMM: Asset not found"); } function checkRate(address token, uint256 tokenAmount, uint256 sweepAmount) internal view { if(tokenAmount == 0 || sweepAmount == 0) revert ZeroAmount(); uint256 tokenFactor = 10 ** IERC20Metadata(token).decimals(); uint256 sweepFactor = 10 ** sweep.decimals(); uint256 rate = tokenAmount * sweepFactor * 1e6 / (tokenFactor * sweepAmount); if(rate > 16e5 || rate < 6e5) revert BadRate(); } /** * @notice Swap tokenIn for tokenOut using balancer exact input swap * @param tokenIn Address to in * @param tokenOut Address to out * @param amountIn Amount of _tokenA * @param amountOutMin Minimum amount out. * @param poolAddress The pool to execute the swap into */ function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMin, address poolAddress) private returns (uint256 amountOut) { bytes32 poolId = IBalancerPool(poolAddress).getPoolId(); address vaultAddress = IBalancerPool(poolAddress).getVault(); TransferHelper.safeTransferFrom(tokenIn, msg.sender, address(this), amountIn); TransferHelper.safeApprove(tokenIn, vaultAddress, amountIn); bytes memory userData; SingleSwap memory singleSwap = SingleSwap( poolId, SwapKind.GIVEN_IN, IAsset(tokenIn), IAsset(tokenOut), amountIn, userData ); FundManagement memory funds = FundManagement(address(this), false, payable(msg.sender), false); uint256 deadline = block.timestamp + DEADLINE_GAP; amountOut = IBalancerVault(vaultAddress).swap(singleSwap, funds, amountOutMin, deadline); } function setMarketMaker(address _marketMaker) external onlyOwner { marketMaker = IMarketMaker(_marketMaker); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC20/extensions/IERC20Metadata.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value) ); require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF'); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST'); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA'); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'STE'); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; interface IBalancerGauge { function claim_rewards() external; function deposit(uint256 _amount) external; function withdraw(uint256 _amount) external; function balanceOf(address _address) external view returns(uint256 _balance); } interface IBalancerVault { struct JoinPoolRequest { IAsset[] assets; uint256[] maxAmountsIn; bytes userData; bool fromInternalBalance; } struct ExitPoolRequest { IAsset[] assets; uint256[] minAmountsOut; bytes userData; bool toInternalBalance; } function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request) external payable; function exitPool(bytes32 poolId, address sender, address recipient, ExitPoolRequest memory request) external payable; function getPoolTokens(bytes32 poolId) external view returns (IAsset[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline) external returns (uint256 amountOut); } interface IAsset { // solhint-disable-previous-line no-empty-blocks } interface IBalancerPool is IERC20Metadata { function getPoolId() external view returns (bytes32); function getVault() external view returns (address); function getRate() external view returns (uint256); function getTokenRate(address) external view returns (uint256); function getScalingFactors() external view returns (uint256[] memory); function getAmplificationParameter() external view returns (uint256, bool, uint256); } struct SingleSwap { bytes32 poolId; SwapKind kind; IAsset assetIn; IAsset assetOut; uint256 amount; bytes userData; } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } interface IComposableStablePoolFactory { function create( string memory name, string memory symbol, IERC20[] memory tokens, uint256 amplificationParameter, IRateProvider[] memory rateProviders, uint256[] memory tokenRateCacheDurations, bool exemptFromYieldProtocolFeeFlag, uint256 swapFeePercentage, address owner, bytes32 salt ) external returns(address poolAddress); } interface IRateProvider { function getRate() external view returns (uint256); } enum JoinKind { INIT, EXACT_TOKENS_IN_FOR_BPT_OUT, TOKEN_IN_FOR_EXACT_BPT_OUT, ALL_TOKENS_IN_FOR_EXACT_BPT_OUT } enum ExitKind { EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, BPT_IN_FOR_EXACT_TOKENS_OUT, EXACT_BPT_IN_FOR_ALL_TOKENS_OUT } enum SwapKind { GIVEN_IN, GIVEN_OUT }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IMarketMaker { function getBuyPrice() external view returns (uint256 price); function buySweep(uint256 usdxAmount) external returns (uint256 sweepAmount); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "./LogExpMath.sol"; /* solhint-disable private-vars-leading-underscore */ library FixedPoint { // solhint-disable no-inline-assembly uint256 internal constant ONE = 1e18; // 18 decimal places uint256 internal constant TWO = 2 * ONE; uint256 internal constant FOUR = 4 * ONE; uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14) // Minimum base for the power function when the exponent is 'free' (larger than ONE). uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18; function add(uint256 a, uint256 b) internal pure returns (uint256) { // Fixed Point addition is the same as regular checked addition uint256 c = a + b; require(c >= a, "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, "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, "MUL_OVERFLOW"); return product / ONE; } function mulUp(uint256 a, uint256 b) internal pure returns (uint256 result) { uint256 product = a * b; require(a == 0 || product / a == b, "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, if x == 0 then the result is zero // // Equivalent to: // result = product == 0 ? 0 : ((product - 1) / FixedPoint.ONE) + 1; assembly { result := mul(iszero(iszero(product)), add(div(sub(product, 1), ONE), 1)) } } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "ZERO_DIVISION"); uint256 aInflated = a * ONE; require(a == 0 || aInflated / a == ONE, "DIV_INTERNAL"); // mul overflow return aInflated / b; } function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) { require(b != 0, "ZERO_DIVISION"); uint256 aInflated = a * ONE; require(a == 0 || aInflated / a == ONE, "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, if x == 0 then the result is zero // // Equivalent to: // result = a == 0 ? 0 : (a * FixedPoint.ONE - 1) / b + 1; assembly { result := mul(iszero(iszero(aInflated)), add(div(sub(aInflated, 1), b), 1)) } } /** * @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above * the true value (that is, the error function expected - actual is always positive). */ function powDown(uint256 x, uint256 y) internal pure returns (uint256) { // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50 // and 80/20 Weighted Pools if (y == ONE) { return x; } else if (y == TWO) { return mulDown(x, x); } else if (y == FOUR) { uint256 square = mulDown(x, x); return mulDown(square, square); } else { uint256 raw = LogExpMath.pow(x, y); uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1); if (raw < maxError) { return 0; } else { return sub(raw, maxError); } } } /** * @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below * the true value (that is, the error function expected - actual is always negative). */ function powUp(uint256 x, uint256 y) internal pure returns (uint256) { // Optimize for when y equals 1.0, 2.0 or 4.0, as those are very simple to implement and occur often in 50/50 // and 80/20 Weighted Pools if (y == ONE) { return x; } else if (y == TWO) { return mulUp(x, x); } else if (y == FOUR) { uint256 square = mulUp(x, x); return mulUp(square, square); } else { uint256 raw = LogExpMath.pow(x, y); uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1); return add(raw, maxError); } } /** * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1. * * Useful when computing the complement for values with some level of relative error, as it strips this error and * prevents intermediate negative values. */ function complement(uint256 x) internal pure returns (uint256 result) { // Equivalent to: // result = (x < ONE) ? (ONE - x) : 0; assembly { result := mul(lt(x, ONE), sub(ONE, x)) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; /* 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 >> 255 == 0, "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, "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, "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, "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, "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.19; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow checks. * Adapted from OpenZeppelin's SafeMath library. */ library BMath { // solhint-disable no-inline-assembly /** * @dev Returns the absolute value of a signed integer. */ function abs(int256 a) internal pure returns (uint256 result) { // Equivalent to: // result = a > 0 ? uint256(a) : uint256(-a) assembly { let s := sar(255, a) result := sub(xor(a, s), s) } } /** * @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, "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), "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, "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), "SUB_OVERFLOW"); return c; } /** * @dev Returns the largest of two numbers of 256 bits. */ function max(uint256 a, uint256 b) internal pure returns (uint256 result) { // Equivalent to: // result = (a < b) ? b : a; assembly { result := sub(a, mul(sub(a, b), lt(a, b))) } } /** * @dev Returns the smallest of two numbers of 256 bits. */ function min(uint256 a, uint256 b) internal pure returns (uint256 result) { // Equivalent to `result = (a < b) ? a : b` assembly { result := sub(a, mul(sub(a, b), gt(a, b))) } } function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a * b; require(a == 0 || c / a == b, "MUL_OVERFLOW"); return c; } function div( uint256 a, uint256 b, bool roundUp ) internal pure returns (uint256) { return roundUp ? divUp(a, b) : divDown(a, b); } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "ZERO_DIVISION"); return a / b; } function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) { require(b != 0, "ZERO_DIVISION"); // Equivalent to: // result = a == 0 ? 0 : 1 + (a - 1) / b; assembly { result := mul(iszero(iszero(a)), add(1, div(sub(a, 1), b))) } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import "./FixedPoint.sol"; import "./Math.sol"; library StableMath { using FixedPoint for uint256; uint256 internal constant _MIN_AMP = 1; uint256 internal constant _MAX_AMP = 5000; uint256 internal constant _AMP_PRECISION = 1e3; uint256 internal constant _MAX_STABLE_TOKENS = 5; function _calculateInvariant(uint256 amplificationParameter, uint256[] memory balances) internal pure returns (uint256) { 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 = BMath.divDown(BMath.mul(D_P, invariant), BMath.mul(balances[j], numTokens)); } prevInvariant = invariant; invariant = BMath.divDown( BMath.mul( // (ampTimesTotal * sum) / AMP_PRECISION + D_P * numTokens (BMath.divDown(BMath.mul(ampTimesTotal, sum), _AMP_PRECISION).add(BMath.mul(D_P, numTokens))), invariant ), // ((ampTimesTotal - _AMP_PRECISION) * invariant) / _AMP_PRECISION + (numTokens + 1) * D_P ( BMath.divDown(BMath.mul((ampTimesTotal - _AMP_PRECISION), invariant), _AMP_PRECISION).add( BMath.mul((numTokens + 1), D_P) ) ) ); if (invariant > prevInvariant) { if (invariant - prevInvariant <= 1) { return invariant; } } else if (prevInvariant - invariant <= 1) { return invariant; } } revert("STABLE_INVARIANT_DIDNT_CONVERGE"); } function _calcOutGivenIn( uint256 amplificationParameter, uint256[] memory balances, uint256 tokenIndexIn, uint256 tokenIndexOut, uint256 tokenAmountIn, uint256 invariant ) internal pure returns (uint256) { balances[tokenIndexIn] = balances[tokenIndexIn].add(tokenAmountIn); uint256 finalBalanceOut = _getTokenBalanceGivenInvariantAndAllOtherBalances( amplificationParameter, balances, invariant, tokenIndexOut ); balances[tokenIndexIn] = balances[tokenIndexIn] - tokenAmountIn; return balances[tokenIndexOut].sub(finalBalanceOut).sub(1); } function _calcInGivenOut( uint256 amplificationParameter, uint256[] memory balances, uint256 tokenIndexIn, uint256 tokenIndexOut, uint256 tokenAmountOut, uint256 invariant ) internal pure returns (uint256) { balances[tokenIndexOut] = balances[tokenIndexOut].sub(tokenAmountOut); uint256 finalBalanceIn = _getTokenBalanceGivenInvariantAndAllOtherBalances( amplificationParameter, balances, invariant, tokenIndexIn ); balances[tokenIndexOut] = balances[tokenIndexOut] + tokenAmountOut; return finalBalanceIn.sub(balances[tokenIndexIn]).add(1); } function _calcBptOutGivenExactTokensIn( uint256 amp, uint256[] memory balances, uint256[] memory amountsIn, uint256 bptTotalSupply, uint256 currentInvariant, uint256 swapFeePercentage ) internal pure returns (uint256) { uint256 sumBalances = 0; for (uint256 i = 0; i < balances.length; i++) { sumBalances = sumBalances.add(balances[i]); } // Calculate the weighted balance ratio without considering fees uint256[] memory balanceRatiosWithFee = new uint256[](amountsIn.length); // The weighted sum of token balance ratios with fee uint256 invariantRatioWithFees = 0; for (uint256 i = 0; i < balances.length; i++) { uint256 currentWeight = balances[i].divDown(sumBalances); balanceRatiosWithFee[i] = balances[i].add(amountsIn[i]).divDown(balances[i]); invariantRatioWithFees = invariantRatioWithFees.add(balanceRatiosWithFee[i].mulDown(currentWeight)); } // Second loop calculates new amounts in, taking into account the fee on the percentage excess uint256[] memory newBalances = new uint256[](balances.length); for (uint256 i = 0; i < balances.length; i++) { uint256 amountInWithoutFee; // Check if the balance ratio is greater than the ideal ratio to charge fees or not if (balanceRatiosWithFee[i] > invariantRatioWithFees) { uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithFees.sub(FixedPoint.ONE)); uint256 taxableAmount = amountsIn[i].sub(nonTaxableAmount); // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50% amountInWithoutFee = nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage)); } else { amountInWithoutFee = amountsIn[i]; } newBalances[i] = balances[i].add(amountInWithoutFee); } uint256 newInvariant = _calculateInvariant(amp, newBalances); uint256 invariantRatio = newInvariant.divDown(currentInvariant); // If the invariant didn't increase for any reason, we simply don't mint BPT if (invariantRatio > FixedPoint.ONE) { return bptTotalSupply.mulDown(invariantRatio - FixedPoint.ONE); } else { return 0; } } function _calcTokenInGivenExactBptOut( uint256 amp, uint256[] memory balances, uint256 tokenIndex, uint256 bptAmountOut, uint256 bptTotalSupply, uint256 currentInvariant, uint256 swapFeePercentage ) internal pure returns (uint256) { // Token in, so we round up overall. uint256 newInvariant = bptTotalSupply.add(bptAmountOut).divUp(bptTotalSupply).mulUp(currentInvariant); // Calculate amount in without fee. uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances( amp, balances, newInvariant, tokenIndex ); uint256 amountInWithoutFee = newBalanceTokenIndex.sub(balances[tokenIndex]); // 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 extra balance is being deposited and used in virtual swaps, and charge swap fees // accordingly. uint256 currentWeight = balances[tokenIndex].divDown(sumBalances); uint256 taxablePercentage = currentWeight.complement(); uint256 taxableAmount = amountInWithoutFee.mulUp(taxablePercentage); uint256 nonTaxableAmount = amountInWithoutFee.sub(taxableAmount); // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50% return nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage)); } /* Flow of calculations: amountsTokenOut -> amountsOutProportional -> amountOutPercentageExcess -> amountOutBeforeFee -> newInvariant -> amountBPTIn */ function _calcBptInGivenExactTokensOut( uint256 amp, uint256[] memory balances, uint256[] memory amountsOut, uint256 bptTotalSupply, uint256 currentInvariant, uint256 swapFeePercentage ) internal pure returns (uint256) { // BPT in, so we round up overall. // First loop calculates the sum of all token balances, which will be used to calculate // the current weights of each token relative to this sum uint256 sumBalances = 0; for (uint256 i = 0; i < balances.length; i++) { sumBalances = sumBalances.add(balances[i]); } // Calculate the weighted balance ratio without considering fees uint256[] memory balanceRatiosWithoutFee = new uint256[](amountsOut.length); uint256 invariantRatioWithoutFees = 0; for (uint256 i = 0; i < balances.length; i++) { uint256 currentWeight = balances[i].divUp(sumBalances); balanceRatiosWithoutFee[i] = balances[i].sub(amountsOut[i]).divUp(balances[i]); invariantRatioWithoutFees = invariantRatioWithoutFees.add(balanceRatiosWithoutFee[i].mulUp(currentWeight)); } // Second loop calculates new amounts in, taking into account the fee on the percentage excess uint256[] memory newBalances = new uint256[](balances.length); for (uint256 i = 0; i < balances.length; i++) { // 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. uint256 amountOutWithFee; if (invariantRatioWithoutFees > balanceRatiosWithoutFee[i]) { uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithoutFees.complement()); uint256 taxableAmount = amountsOut[i].sub(nonTaxableAmount); // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50% amountOutWithFee = nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage)); } else { amountOutWithFee = amountsOut[i]; } newBalances[i] = balances[i].sub(amountOutWithFee); } uint256 newInvariant = _calculateInvariant(amp, newBalances); uint256 invariantRatio = newInvariant.divDown(currentInvariant); // return amountBPTIn return bptTotalSupply.mulUp(invariantRatio.complement()); } 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 = BMath.divDown(BMath.mul(BMath.mul(P_D, balances[j]), balances.length), invariant); sum = sum.add(balances[j]); } // No need to use safe Bmath, based on the loop above `sum` is greater than or equal to `balances[tokenIndex]` sum = sum - balances[tokenIndex]; uint256 inv2 = BMath.mul(invariant, invariant); // We remove the balance from c by multiplying it uint256 c = BMath.mul( BMath.mul(BMath.divUp(inv2, BMath.mul(ampTimesTotal, P_D)), _AMP_PRECISION), balances[tokenIndex] ); uint256 b = sum.add(BMath.mul(BMath.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 = BMath.divUp(inv2.add(c), invariant.add(b)); for (uint256 i = 0; i < 255; i++) { prevTokenBalance = tokenBalance; tokenBalance = BMath.divUp( BMath.mul(tokenBalance, tokenBalance).add(c), BMath.mul(tokenBalance, 2).add(b).sub(invariant) ); if (tokenBalance > prevTokenBalance) { if (tokenBalance - prevTokenBalance <= 1) { return tokenBalance; } } else if (prevTokenBalance - tokenBalance <= 1) { return tokenBalance; } } revert("STABLE_GET_BALANCE_DIDNT_CONVERGE"); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface IPriceFeed { function latestAnswer() external view returns (int256); function latestTimestamp() external view returns (uint256); function latestRound() external view returns (uint256); function getAnswer(uint256 roundId) external view returns (int256); function getTimestamp(uint256 roundId) external view returns (uint256); function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData( uint80 _roundId ) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } library ChainlinkLibrary { uint8 constant USD_DECIMALS = 6; function getDecimals(IPriceFeed oracle) internal view returns (uint8) { return oracle.decimals(); } function getPrice(IPriceFeed oracle) internal view returns (uint256) { ( uint80 roundID, int256 price, , uint256 timeStamp, uint80 answeredInRound ) = oracle.latestRoundData(); require(answeredInRound >= roundID, "Old data"); require(timeStamp > 0, "Round not complete"); return uint256(price); } function getPrice( IPriceFeed oracle, IPriceFeed sequencerOracle, uint256 frequency ) internal view returns (uint256) { if (address(sequencerOracle) != address(0)) checkUptime(sequencerOracle); (uint256 roundId, int256 price, , uint256 updatedAt, ) = oracle .latestRoundData(); require(price > 0 && roundId != 0 && updatedAt != 0, "Invalid Price"); if (frequency > 0) require(block.timestamp - updatedAt <= frequency, "Stale Price"); return uint256(price); } function checkUptime(IPriceFeed sequencerOracle) internal view { (, int256 answer, uint256 startedAt, , ) = sequencerOracle .latestRoundData(); require(answer <= 0, "Sequencer Down"); // 0: Sequencer is up, 1: Sequencer is down require(block.timestamp - startedAt > 1 hours, "Grace Period Not Over"); } function convertTokenToToken( uint256 amount0, uint8 token0Decimals, uint8 token1Decimals, IPriceFeed oracle0, IPriceFeed oracle1 ) internal view returns (uint256 amount1) { uint256 price0 = getPrice(oracle0); uint256 price1 = getPrice(oracle1); amount1 = (amount0 * price0 * (10 ** token1Decimals)) / (price1 * (10 ** token0Decimals)); } function convertTokenToUsd( uint256 amount, uint8 tokenDecimals, IPriceFeed oracle ) internal view returns (uint256 amountUsd) { uint8 decimals = getDecimals(oracle); uint256 price = getPrice(oracle); amountUsd = (amount * price * (10 ** USD_DECIMALS)) / 10 ** (decimals + tokenDecimals); } function convertUsdToToken( uint256 amountUsd, uint256 tokenDecimals, IPriceFeed oracle ) internal view returns (uint256 amount) { uint8 decimals = getDecimals(oracle); uint256 price = getPrice(oracle); amount = (amountUsd * 10 ** (decimals + tokenDecimals)) / (price * (10 ** USD_DECIMALS)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; interface ISweep { struct Minter { uint256 maxAmount; uint256 mintedAmount; bool isListed; bool isEnabled; } function isMintingAllowed() external view returns (bool); function DEFAULT_ADMIN_ADDRESS() external view returns (address); function balancer() external view returns (address); function treasury() external view returns (address); function allowance( address holder, address spender ) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); function decimals() external view returns (uint8); function decreaseAllowance( address spender, uint256 subtractedValue ) external returns (bool); function isValidMinter(address) external view returns (bool); function amm() external view returns (address); function ammPrice() external view returns (uint256); function twaPrice() external view returns (uint256); function increaseAllowance( address spender, uint256 addedValue ) external returns (bool); function name() external view returns (string memory); function owner() external view returns (address); function fastMultisig() external view returns (address); function burn(uint256 amount) external; function mint(uint256 amount) external; function minters(address minterAaddress) external returns (Minter memory); function minterAddresses(uint256 index) external view returns (address); function getMinters() external view returns (address[] memory); function targetPrice() external view returns (uint256); function interestRate() external view returns (int256); function periodStart() external view returns (uint256); function stepValue() external view returns (int256); function arbSpread() external view returns (uint256); function refreshInterestRate(int256 newInterestRate, uint256 newPeriodStart) external; function setTargetPrice( uint256 currentTargetPrice, uint256 nextTargetPrice ) external; function setInterestRate( int256 currentInterestRate, int256 nextInterestRate ) external; function setPeriodStart( uint256 currentPeriodStart, uint256 nextPeriodStart ) external; function startNewPeriod() external; function symbol() external view returns (string memory); function totalSupply() external view returns (uint256); function convertToUSD(uint256 amount) external view returns (uint256); function convertToSWEEP(uint256 amount) external view returns (uint256); function transfer( address recipient, uint256 amount ) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); }
{ "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":"_sweep","type":"address"},{"internalType":"address","name":"_base","type":"address"},{"internalType":"address","name":"_sequencer","type":"address"},{"internalType":"address","name":"_oracleBase","type":"address"},{"internalType":"uint256","name":"_oracleBaseUpdateFrequency","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadRate","type":"error"},{"inputs":[],"name":"NotOwnerOrGov","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"usdxAmount","type":"uint256"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"name":"Sold","type":"event"},{"inputs":[],"name":"base","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usdxAddress","type":"address"},{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"buySweep","outputs":[{"internalType":"uint256","name":"sweepAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getPositions","outputs":[{"internalType":"uint256","name":"usdxAmount","type":"uint256"},{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"lp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTWAPrice","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketMaker","outputs":[{"internalType":"contract IMarketMaker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleBase","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleBaseUpdateFrequency","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"contract IBalancerPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usdxAddress","type":"address"},{"internalType":"uint256","name":"sweepAmount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"sellSweep","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sequencer","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_marketMaker","type":"address"}],"name":"setMarketMaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"","type":"uint24"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"}],"name":"swapExactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sweep","outputs":[{"internalType":"contract ISweep","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IBalancerVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101206040523480156200001257600080fd5b5060405162002ad138038062002ad183398101604081905262000035916200007b565b6001600160a01b0394851660a052928416608052831660c05290911660e05261010052620000e2565b80516001600160a01b03811681146200007657600080fd5b919050565b600080600080600060a086880312156200009457600080fd5b6200009f866200005e565b9450620000af602087016200005e565b9350620000bf604087016200005e565b9250620000cf606087016200005e565b9150608086015190509295509295909350565b60805160a05160c05160e0516101005161291e620001b3600039600081816102680152610ecf0152600081816102390152610eae0152600081816101e301528181610e600152610e8d0152600081816101860152818161047f0152818161057a015281816105b8015281816106d20152818161091101528181610952015281816109aa01528181610d2a01528181610f910152818161102f015261125001526000818161020a015281816104510152818161083c0152818161086c01528181610a300152610d58015261291e6000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806359879099116100a25780638c60c71c116100715780638c60c71c1461028a57806398d5fdca1461029d578063eda28b11146102a5578063f54c42d7146102b8578063fbfa77cf146102cb57600080fd5b8063598790991461022c5780635c1bba3814610234578063679aefce1461025b57806375cdf6491461026357600080fd5b806338da412e116100de57806338da412e146101a85780634437152a146101c95780634562aee3146101de5780635001f3b51461020557600080fd5b806316f0115b146101105780631f21f9af1461014057806330e005961461015357806335faa41614610181575b600080fd5b600154610123906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600254610123906001600160a01b031681565b6101666101613660046121b9565b6102de565b60408051938452602084019290925290820152606001610137565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6101b63660046121ea565b61052b565b604051908152602001610137565b6101dc6101d736600461221f565b6105b6565b005b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106bf565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106ce565b6101bb7f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6102983660046121ea565b610761565b6101bb61098b565b6101bb6102b336600461223c565b610f65565b6101dc6102c636600461221f565b610f8f565b600054610123906001600160a01b031681565b6000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e291906122bc565b6040518263ffffffff1660e01b815260040161040091815260200190565b600060405180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261044591908101906123ab565b509150915060006104767f000000000000000000000000000000000000000000000000000000000000000084611105565b905060006104a47f000000000000000000000000000000000000000000000000000000000000000085611105565b6001549091506000906104c0906001600160a01b031686611105565b9050838360ff16815181106104d7576104d7612479565b60200260200101519750838260ff16815181106104f6576104f6612479565b60200260200101519650838160ff168151811061051557610515612479565b6020026020010151955050505050509193909250565b60007f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb35205439957278360405161055e91815260200190565b60405180910390a16105718483856111b2565b6001546105ae907f0000000000000000000000000000000000000000000000000000000000000000908690869086906001600160a01b0316611345565b949350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610638919061229f565b6001600160a01b0316336001600160a01b03161461069d5760405162461bcd60e51b815260206004820152601b60248201527f42616c616e636572414d4d3a204e6f7420476f7665726e616e6365000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006106c961098b565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dc38679c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075291906122bc565b6106c99064e8d4a510006124a5565b60007f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef18360405161079491815260200190565b60405180910390a16002546001600160a01b03161580159061083257506107b961098b565b600260009054906101000a90046001600160a01b03166001600160a01b031663018a25e86040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083091906122bc565b105b1561093c576108637f0000000000000000000000000000000000000000000000000000000000000000333086611559565b60025461089b907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b03168561165b565b6002546040516369ae990b60e01b8152600481018590526001600160a01b03909116906369ae990b906024016020604051808303816000875af11580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a91906122bc565b90506109377f0000000000000000000000000000000000000000000000000000000000000000338361175b565b610984565b6109478484846111b2565b6001546105ae9085907f000000000000000000000000000000000000000000000000000000000000000090869086906001600160a01b0316611345565b9392505050565b6001546000906001600160a01b03166109a65750621e848090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a91906124bc565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab091906124bc565b90506000610abe82846124df565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631dd746ea6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3d91908101906124f8565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316636daccffa6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb89190612542565b50509050600080600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c36919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb91906122bc565b6040518263ffffffff1660e01b8152600401610cd991815260200190565b600060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d1e91908101906123ab565b50915091506000610d4f7f000000000000000000000000000000000000000000000000000000000000000084611105565b90506000610d7d7f000000000000000000000000000000000000000000000000000000000000000085611105565b6040805160028082526060820183529293506000929091602083019080368337019050509050838360ff1681518110610db857610db8612479565b602002602001015181600081518110610dd357610dd3612479565b6020908102919091010152610de988600a61265b565b848360ff1681518110610dfe57610dfe612479565b6020026020010151610e1091906124a5565b81600181518110610e2357610e23612479565b6020026020010181815250506000610e3b8783611854565b90506000610e57888460006001670de0b6b3a764000087611a3c565b90506000610e847f0000000000000000000000000000000000000000000000000000000000000000611b1e565b90506000610ef37f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611b82565b90508b610f008f8461266a565b610f0a919061266a565b610f1590600a61265b565b818c8960ff1681518110610f2b57610f2b612479565b602002602001015185610f3e91906124a5565b610f4891906124a5565b610f529190612683565b9e50505050505050505050505050505090565b600154600090610f859087908790869086906001600160a01b0316611345565b9695505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611011919061229f565b6001600160a01b0316336001600160a01b0316141580156110c557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110af919061229f565b6001600160a01b0316336001600160a01b031614155b156110e3576040516338ae11af60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82518160ff16101561116357836001600160a01b0316838260ff168151811061113457611134612479565b60200260200101516001600160a01b0316036111515790506111ac565b8061115b816126a5565b915050611109565b5060405162461bcd60e51b815260206004820152601c60248201527f42616c616e636572414d4d3a204173736574206e6f7420666f756e64000000006044820152606401610694565b92915050565b8115806111bd575080155b156111db57604051631f2a200560e01b815260040160405180910390fd5b6000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561121b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123f91906124bc565b61124a90600a61265b565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d091906124bc565b6112db90600a61265b565b905060006112e984846124a5565b6112f383876124a5565b61130090620f42406124a5565b61130a9190612683565b905062186a0081118061131f5750620927c081105b1561133d5760405163491dee2160e01b815260040160405180910390fd5b505050505050565b600080826001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113aa91906122bc565b90506000836001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611410919061229f565b905061141e88333089611559565b61142988828861165b565b606060006040518060c0016040528085815260200160006001811115611451576114516126c4565b81526020018b6001600160a01b031681526020018a6001600160a01b0316815260200189815260200183815250905060006040518060800160405280306001600160a01b03168152602001600015158152602001336001600160a01b03168152602001600015158152509050600061038461ffff16426114d191906126da565b6040516352bbbe2960e01b81529091506001600160a01b038616906352bbbe299061150690869086908e90879060040161273d565b6020604051808303816000875af1158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906122bc565b9c9b505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916115bd919061281b565b6000604051808303816000865af19150503d80600081146115fa576040519150601f19603f3d011682016040523d82523d6000602084013e6115ff565b606091505b50915091508180156116295750805115806116295750808060200190518101906116299190612837565b61133d5760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610694565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916116b7919061281b565b6000604051808303816000865af19150503d80600081146116f4576040519150601f19603f3d011682016040523d82523d6000602084013e6116f9565b606091505b50915091508180156117235750805115806117235750808060200190518101906117239190612837565b6117545760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610694565b5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117b7919061281b565b6000604051808303816000865af19150503d80600081146117f4576040519150601f19603f3d011682016040523d82523d6000602084013e6117f9565b606091505b50915091508180156118235750805115806118235750808060200190518101906118239190612837565b6117545760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610694565b80516000908190815b818110156118a55761189185828151811061187a5761187a612479565b602002602001015184611cc490919063ffffffff16565b92508061189d81612852565b91505061185d565b50816000036118b9576000925050506111ac565b600082816118c784896124a5565b905060005b60ff8110156119f3578260005b8681101561192a576119166118ee8387611d12565b6119118c848151811061190357611903612479565b60200260200101518a611d12565b611d71565b91508061192281612852565b9150506118d9565b5083945061199161196261195c611941848a611d12565b61195661194e888d611d12565b6103e8611d71565b90611cc4565b86611d12565b6119116119796119738a60016126da565b85611d12565b61195661194e61198b6103e88a61286b565b8a611d12565b9350848411156119c05760016119a7868661286b565b116119bb57839750505050505050506111ac565b6119e0565b60016119cc858761286b565b116119e057839750505050505050506111ac565b50806119eb81612852565b9150506118cc565b5060405162461bcd60e51b815260206004820152601f60248201527f535441424c455f494e56415249414e545f4449444e545f434f4e5645524745006044820152606401610694565b6000611a6a83878781518110611a5457611a54612479565b6020026020010151611cc490919063ffffffff16565b868681518110611a7c57611a7c612479565b6020026020010181815250506000611a9688888588611dbd565b905083878781518110611aab57611aab612479565b6020026020010151611abd919061286b565b878781518110611acf57611acf612479565b602002602001018181525050611b126001611b0c838a8981518110611af657611af6612479565b602002602001015161201390919063ffffffff16565b90612013565b98975050505050505050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b5e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac91906124bc565b60006001600160a01b03831615611b9c57611b9c83612060565b6000806000866001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c039190612898565b50935050925069ffffffffffffffffffff169250600082138015611c2657508215155b8015611c3157508015155b611c6d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420507269636560981b6044820152606401610694565b8415611cba5784611c7e824261286b565b1115611cba5760405162461bcd60e51b815260206004820152600b60248201526a5374616c6520507269636560a81b6044820152606401610694565b5095945050505050565b600080611cd183856126da565b9050838110156109845760405162461bcd60e51b815260206004820152600c60248201526b4144445f4f564552464c4f5760a01b6044820152606401610694565b600080611d1f83856124a5565b9050831580611d36575082611d348583612683565b145b6109845760405162461bcd60e51b815260206004820152600c60248201526b4d554c5f4f564552464c4f5760a01b6044820152606401610694565b600081600003611db35760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b6109848284612683565b600080845186611dcd91906124a5565b9050600085600081518110611de457611de4612479565b602002602001015190506000865187600081518110611e0557611e05612479565b6020026020010151611e1791906124a5565b905060015b8751811015611e8657611e5b611e55611e4e848b8581518110611e4157611e41612479565b6020026020010151611d12565b8a51611d12565b88611d71565b9150611e7288828151811061187a5761187a612479565b925080611e7e81612852565b915050611e1c565b50868581518110611e9957611e99612479565b602002602001015182611eac919061286b565b91506000611eba8788611d12565b90506000611ef1611edf611ed784611ed28988611d12565b612165565b6103e8611d12565b8a8981518110611e4157611e41612479565b90506000611f0c611f05611ed78b89611d71565b8690611cc4565b9050600080611f28611f1e8686611cc4565b611ed28d86611cc4565b905060005b60ff811015611fc057819250611f5d611f4a866119568586611d12565b611ed28e611b0c88611956886002611d12565b915082821115611f8d576001611f73848461286b565b11611f88575097506105ae9650505050505050565b611fae565b6001611f99838561286b565b11611fae575097506105ae9650505050505050565b80611fb881612852565b915050611f2d565b5060405162461bcd60e51b815260206004820152602160248201527f535441424c455f4745545f42414c414e43455f4449444e545f434f4e564552476044820152604560f81b6064820152608401610694565b6000828211156120545760405162461bcd60e51b815260206004820152600c60248201526b5355425f4f564552464c4f5760a01b6044820152606401610694565b60006105ae838561286b565b600080826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156120a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c59190612898565b50509250925050600082131561210e5760405162461bcd60e51b815260206004820152600e60248201526d29b2b8bab2b731b2b9102237bbb760911b6044820152606401610694565b610e1061211b824261286b565b116121605760405162461bcd60e51b815260206004820152601560248201527423b930b1b2902832b934b7b2102737ba1027bb32b960591b6044820152606401610694565b505050565b6000816000036121a75760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b50811515600019909201046001010290565b6000602082840312156121cb57600080fd5b5035919050565b6001600160a01b03811681146121e757600080fd5b50565b6000806000606084860312156121ff57600080fd5b833561220a816121d2565b95602085013595506040909401359392505050565b60006020828403121561223157600080fd5b8135610984816121d2565b600080600080600060a0868803121561225457600080fd5b853561225f816121d2565b9450602086013561226f816121d2565b9350604086013562ffffff8116811461228757600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156122b157600080fd5b8151610984816121d2565b6000602082840312156122ce57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612314576123146122d5565b604052919050565b600067ffffffffffffffff821115612336576123366122d5565b5060051b60200190565b600082601f83011261235157600080fd5b815160206123666123618361231c565b6122eb565b82815260059290921b8401810191818101908684111561238557600080fd5b8286015b848110156123a05780518352918301918301612389565b509695505050505050565b6000806000606084860312156123c057600080fd5b835167ffffffffffffffff808211156123d857600080fd5b818601915086601f8301126123ec57600080fd5b815160206123fc6123618361231c565b82815260059290921b8401810191818101908a84111561241b57600080fd5b948201945b83861015612442578551612433816121d2565b82529482019490820190612420565b9189015191975090935050508082111561245b57600080fd5b5061246886828701612340565b925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176111ac576111ac61248f565b6000602082840312156124ce57600080fd5b815160ff8116811461098457600080fd5b60ff82811682821603908111156111ac576111ac61248f565b60006020828403121561250a57600080fd5b815167ffffffffffffffff81111561252157600080fd5b6105ae84828501612340565b8051801515811461253d57600080fd5b919050565b60008060006060848603121561255757600080fd5b835192506125676020850161252d565b9150604084015190509250925092565b600181815b808511156125b25781600019048211156125985761259861248f565b808516156125a557918102915b93841c939080029061257c565b509250929050565b6000826125c9575060016111ac565b816125d6575060006111ac565b81600181146125ec57600281146125f657612612565b60019150506111ac565b60ff8411156126075761260761248f565b50506001821b6111ac565b5060208310610133831016604e8410600b8410161715612635575081810a6111ac565b61263f8383612577565b80600019048211156126535761265361248f565b029392505050565b600061098460ff8416836125ba565b60ff81811683821601908111156111ac576111ac61248f565b6000826126a057634e487b7160e01b600052601260045260246000fd5b500490565b600060ff821660ff81036126bb576126bb61248f565b60010192915050565b634e487b7160e01b600052602160045260246000fd5b808201808211156111ac576111ac61248f565b60005b838110156127085781810151838201526020016126f0565b50506000910152565b600081518084526127298160208601602086016126ed565b601f01601f19169290920160200192915050565b60e08152845160e0820152600060208601516002811061276d57634e487b7160e01b600052602160045260246000fd5b61010083015260408601516001600160a01b031661012083015260608601516127a26101408401826001600160a01b03169052565b50608086015161016083015260a086015160c06101808401526127c96101a0840182612711565b915050612809602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b6000825161282d8184602087016126ed565b9190910192915050565b60006020828403121561284957600080fd5b6109848261252d565b6000600182016128645761286461248f565b5060010190565b818103818111156111ac576111ac61248f565b805169ffffffffffffffffffff8116811461253d57600080fd5b600080600080600060a086880312156128b057600080fd5b6128b98661287e565b94506020860151935060408601519250606086015191506128dc6080870161287e565b9050929550929590935056fea264697066735822122034d6076b22da7cecbf8a6b93581d263c4fcee103111e1a043ce67842daccaaa964736f6c63430008130033000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435740000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f70000000000000000000000000000000000000000000000000000000000015180
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061010b5760003560e01c806359879099116100a25780638c60c71c116100715780638c60c71c1461028a57806398d5fdca1461029d578063eda28b11146102a5578063f54c42d7146102b8578063fbfa77cf146102cb57600080fd5b8063598790991461022c5780635c1bba3814610234578063679aefce1461025b57806375cdf6491461026357600080fd5b806338da412e116100de57806338da412e146101a85780634437152a146101c95780634562aee3146101de5780635001f3b51461020557600080fd5b806316f0115b146101105780631f21f9af1461014057806330e005961461015357806335faa41614610181575b600080fd5b600154610123906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b600254610123906001600160a01b031681565b6101666101613660046121b9565b6102de565b60408051938452602084019290925290820152606001610137565b6101237f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357481565b6101bb6101b63660046121ea565b61052b565b604051908152602001610137565b6101dc6101d736600461221f565b6105b6565b005b6101237f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f781565b6101237f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335981565b6101bb6106bf565b6101237f000000000000000000000000000000000000000000000000000000000000000081565b6101bb6106ce565b6101bb7f000000000000000000000000000000000000000000000000000000000001518081565b6101bb6102983660046121ea565b610761565b6101bb61098b565b6101bb6102b336600461223c565b610f65565b6101dc6102c636600461221f565b610f8f565b600054610123906001600160a01b031681565b6000806000806000600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035d919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e291906122bc565b6040518263ffffffff1660e01b815260040161040091815260200190565b600060405180830381865afa15801561041d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261044591908101906123ab565b509150915060006104767f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335984611105565b905060006104a47f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357485611105565b6001549091506000906104c0906001600160a01b031686611105565b9050838360ff16815181106104d7576104d7612479565b60200260200101519750838260ff16815181106104f6576104f6612479565b60200260200101519650838160ff168151811061051557610515612479565b6020026020010151955050505050509193909250565b60007f92f64ca637d023f354075a4be751b169c1a8a9ccb6d33cdd0cb35205439957278360405161055e91815260200190565b60405180910390a16105718483856111b2565b6001546105ae907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574908690869086906001600160a01b0316611345565b949350505050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610638919061229f565b6001600160a01b0316336001600160a01b03161461069d5760405162461bcd60e51b815260206004820152601b60248201527f42616c616e636572414d4d3a204e6f7420476f7665726e616e6365000000000060448201526064015b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b60006106c961098b565b905090565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663dc38679c6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075291906122bc565b6106c99064e8d4a510006124a5565b60007f4e08ba899977cf7d4c2964bce71c6b9a7ef76ee5166a4c1249a1e08016e33ef18360405161079491815260200190565b60405180910390a16002546001600160a01b03161580159061083257506107b961098b565b600260009054906101000a90046001600160a01b03166001600160a01b031663018a25e86040518163ffffffff1660e01b8152600401602060405180830381865afa15801561080c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083091906122bc565b105b1561093c576108637f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359333086611559565b60025461089b907f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359906001600160a01b03168561165b565b6002546040516369ae990b60e01b8152600481018590526001600160a01b03909116906369ae990b906024016020604051808303816000875af11580156108e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090a91906122bc565b90506109377f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574338361175b565b610984565b6109478484846111b2565b6001546105ae9085907f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357490869086906001600160a01b0316611345565b9392505050565b6001546000906001600160a01b03166109a65750621e848090565b60007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a91906124bc565b905060007f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33596001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab091906124bc565b90506000610abe82846124df565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316631dd746ea6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3d91908101906124f8565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316636daccffa6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610b94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb89190612542565b50509050600080600160009054906101000a90046001600160a01b03166001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c36919061229f565b6001600160a01b031663f94d4668600160009054906101000a90046001600160a01b03166001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb91906122bc565b6040518263ffffffff1660e01b8152600401610cd991815260200190565b600060405180830381865afa158015610cf6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d1e91908101906123ab565b50915091506000610d4f7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d4357484611105565b90506000610d7d7f0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c335985611105565b6040805160028082526060820183529293506000929091602083019080368337019050509050838360ff1681518110610db857610db8612479565b602002602001015181600081518110610dd357610dd3612479565b6020908102919091010152610de988600a61265b565b848360ff1681518110610dfe57610dfe612479565b6020026020010151610e1091906124a5565b81600181518110610e2357610e23612479565b6020026020010181815250506000610e3b8783611854565b90506000610e57888460006001670de0b6b3a764000087611a3c565b90506000610e847f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f7611b1e565b90506000610ef37f000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f77f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000015180611b82565b90508b610f008f8461266a565b610f0a919061266a565b610f1590600a61265b565b818c8960ff1681518110610f2b57610f2b612479565b602002602001015185610f3e91906124a5565b610f4891906124a5565b610f529190612683565b9e50505050505050505050505050505090565b600154600090610f859087908790869086906001600160a01b0316611345565b9695505050505050565b7f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663baf4a3126040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611011919061229f565b6001600160a01b0316336001600160a01b0316141580156110c557507f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110af919061229f565b6001600160a01b0316336001600160a01b031614155b156110e3576040516338ae11af60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b82518160ff16101561116357836001600160a01b0316838260ff168151811061113457611134612479565b60200260200101516001600160a01b0316036111515790506111ac565b8061115b816126a5565b915050611109565b5060405162461bcd60e51b815260206004820152601c60248201527f42616c616e636572414d4d3a204173736574206e6f7420666f756e64000000006044820152606401610694565b92915050565b8115806111bd575080155b156111db57604051631f2a200560e01b815260040160405180910390fd5b6000836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561121b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123f91906124bc565b61124a90600a61265b565b905060007f000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d091906124bc565b6112db90600a61265b565b905060006112e984846124a5565b6112f383876124a5565b61130090620f42406124a5565b61130a9190612683565b905062186a0081118061131f5750620927c081105b1561133d5760405163491dee2160e01b815260040160405180910390fd5b505050505050565b600080826001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015611386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113aa91906122bc565b90506000836001600160a01b0316638d928af86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611410919061229f565b905061141e88333089611559565b61142988828861165b565b606060006040518060c0016040528085815260200160006001811115611451576114516126c4565b81526020018b6001600160a01b031681526020018a6001600160a01b0316815260200189815260200183815250905060006040518060800160405280306001600160a01b03168152602001600015158152602001336001600160a01b03168152602001600015158152509050600061038461ffff16426114d191906126da565b6040516352bbbe2960e01b81529091506001600160a01b038616906352bbbe299061150690869086908e90879060040161273d565b6020604051808303816000875af1158015611525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154991906122bc565b9c9b505050505050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916115bd919061281b565b6000604051808303816000865af19150503d80600081146115fa576040519150601f19603f3d011682016040523d82523d6000602084013e6115ff565b606091505b50915091508180156116295750805115806116295750808060200190518101906116299190612837565b61133d5760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b6044820152606401610694565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916116b7919061281b565b6000604051808303816000865af19150503d80600081146116f4576040519150601f19603f3d011682016040523d82523d6000602084013e6116f9565b606091505b50915091508180156117235750805115806117235750808060200190518101906117239190612837565b6117545760405162461bcd60e51b8152602060048201526002602482015261534160f01b6044820152606401610694565b5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117b7919061281b565b6000604051808303816000865af19150503d80600081146117f4576040519150601f19603f3d011682016040523d82523d6000602084013e6117f9565b606091505b50915091508180156118235750805115806118235750808060200190518101906118239190612837565b6117545760405162461bcd60e51b815260206004820152600260248201526114d560f21b6044820152606401610694565b80516000908190815b818110156118a55761189185828151811061187a5761187a612479565b602002602001015184611cc490919063ffffffff16565b92508061189d81612852565b91505061185d565b50816000036118b9576000925050506111ac565b600082816118c784896124a5565b905060005b60ff8110156119f3578260005b8681101561192a576119166118ee8387611d12565b6119118c848151811061190357611903612479565b60200260200101518a611d12565b611d71565b91508061192281612852565b9150506118d9565b5083945061199161196261195c611941848a611d12565b61195661194e888d611d12565b6103e8611d71565b90611cc4565b86611d12565b6119116119796119738a60016126da565b85611d12565b61195661194e61198b6103e88a61286b565b8a611d12565b9350848411156119c05760016119a7868661286b565b116119bb57839750505050505050506111ac565b6119e0565b60016119cc858761286b565b116119e057839750505050505050506111ac565b50806119eb81612852565b9150506118cc565b5060405162461bcd60e51b815260206004820152601f60248201527f535441424c455f494e56415249414e545f4449444e545f434f4e5645524745006044820152606401610694565b6000611a6a83878781518110611a5457611a54612479565b6020026020010151611cc490919063ffffffff16565b868681518110611a7c57611a7c612479565b6020026020010181815250506000611a9688888588611dbd565b905083878781518110611aab57611aab612479565b6020026020010151611abd919061286b565b878781518110611acf57611acf612479565b602002602001018181525050611b126001611b0c838a8981518110611af657611af6612479565b602002602001015161201390919063ffffffff16565b90612013565b98975050505050505050565b6000816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b5e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac91906124bc565b60006001600160a01b03831615611b9c57611b9c83612060565b6000806000866001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c039190612898565b50935050925069ffffffffffffffffffff169250600082138015611c2657508215155b8015611c3157508015155b611c6d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c696420507269636560981b6044820152606401610694565b8415611cba5784611c7e824261286b565b1115611cba5760405162461bcd60e51b815260206004820152600b60248201526a5374616c6520507269636560a81b6044820152606401610694565b5095945050505050565b600080611cd183856126da565b9050838110156109845760405162461bcd60e51b815260206004820152600c60248201526b4144445f4f564552464c4f5760a01b6044820152606401610694565b600080611d1f83856124a5565b9050831580611d36575082611d348583612683565b145b6109845760405162461bcd60e51b815260206004820152600c60248201526b4d554c5f4f564552464c4f5760a01b6044820152606401610694565b600081600003611db35760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b6109848284612683565b600080845186611dcd91906124a5565b9050600085600081518110611de457611de4612479565b602002602001015190506000865187600081518110611e0557611e05612479565b6020026020010151611e1791906124a5565b905060015b8751811015611e8657611e5b611e55611e4e848b8581518110611e4157611e41612479565b6020026020010151611d12565b8a51611d12565b88611d71565b9150611e7288828151811061187a5761187a612479565b925080611e7e81612852565b915050611e1c565b50868581518110611e9957611e99612479565b602002602001015182611eac919061286b565b91506000611eba8788611d12565b90506000611ef1611edf611ed784611ed28988611d12565b612165565b6103e8611d12565b8a8981518110611e4157611e41612479565b90506000611f0c611f05611ed78b89611d71565b8690611cc4565b9050600080611f28611f1e8686611cc4565b611ed28d86611cc4565b905060005b60ff811015611fc057819250611f5d611f4a866119568586611d12565b611ed28e611b0c88611956886002611d12565b915082821115611f8d576001611f73848461286b565b11611f88575097506105ae9650505050505050565b611fae565b6001611f99838561286b565b11611fae575097506105ae9650505050505050565b80611fb881612852565b915050611f2d565b5060405162461bcd60e51b815260206004820152602160248201527f535441424c455f4745545f42414c414e43455f4449444e545f434f4e564552476044820152604560f81b6064820152608401610694565b6000828211156120545760405162461bcd60e51b815260206004820152600c60248201526b5355425f4f564552464c4f5760a01b6044820152606401610694565b60006105ae838561286b565b600080826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156120a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c59190612898565b50509250925050600082131561210e5760405162461bcd60e51b815260206004820152600e60248201526d29b2b8bab2b731b2b9102237bbb760911b6044820152606401610694565b610e1061211b824261286b565b116121605760405162461bcd60e51b815260206004820152601560248201527423b930b1b2902832b934b7b2102737ba1027bb32b960591b6044820152606401610694565b505050565b6000816000036121a75760405162461bcd60e51b815260206004820152600d60248201526c2d22a927afa224ab24a9a4a7a760991b6044820152606401610694565b50811515600019909201046001010290565b6000602082840312156121cb57600080fd5b5035919050565b6001600160a01b03811681146121e757600080fd5b50565b6000806000606084860312156121ff57600080fd5b833561220a816121d2565b95602085013595506040909401359392505050565b60006020828403121561223157600080fd5b8135610984816121d2565b600080600080600060a0868803121561225457600080fd5b853561225f816121d2565b9450602086013561226f816121d2565b9350604086013562ffffff8116811461228757600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156122b157600080fd5b8151610984816121d2565b6000602082840312156122ce57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612314576123146122d5565b604052919050565b600067ffffffffffffffff821115612336576123366122d5565b5060051b60200190565b600082601f83011261235157600080fd5b815160206123666123618361231c565b6122eb565b82815260059290921b8401810191818101908684111561238557600080fd5b8286015b848110156123a05780518352918301918301612389565b509695505050505050565b6000806000606084860312156123c057600080fd5b835167ffffffffffffffff808211156123d857600080fd5b818601915086601f8301126123ec57600080fd5b815160206123fc6123618361231c565b82815260059290921b8401810191818101908a84111561241b57600080fd5b948201945b83861015612442578551612433816121d2565b82529482019490820190612420565b9189015191975090935050508082111561245b57600080fd5b5061246886828701612340565b925050604084015190509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176111ac576111ac61248f565b6000602082840312156124ce57600080fd5b815160ff8116811461098457600080fd5b60ff82811682821603908111156111ac576111ac61248f565b60006020828403121561250a57600080fd5b815167ffffffffffffffff81111561252157600080fd5b6105ae84828501612340565b8051801515811461253d57600080fd5b919050565b60008060006060848603121561255757600080fd5b835192506125676020850161252d565b9150604084015190509250925092565b600181815b808511156125b25781600019048211156125985761259861248f565b808516156125a557918102915b93841c939080029061257c565b509250929050565b6000826125c9575060016111ac565b816125d6575060006111ac565b81600181146125ec57600281146125f657612612565b60019150506111ac565b60ff8411156126075761260761248f565b50506001821b6111ac565b5060208310610133831016604e8410600b8410161715612635575081810a6111ac565b61263f8383612577565b80600019048211156126535761265361248f565b029392505050565b600061098460ff8416836125ba565b60ff81811683821601908111156111ac576111ac61248f565b6000826126a057634e487b7160e01b600052601260045260246000fd5b500490565b600060ff821660ff81036126bb576126bb61248f565b60010192915050565b634e487b7160e01b600052602160045260246000fd5b808201808211156111ac576111ac61248f565b60005b838110156127085781810151838201526020016126f0565b50506000910152565b600081518084526127298160208601602086016126ed565b601f01601f19169290920160200192915050565b60e08152845160e0820152600060208601516002811061276d57634e487b7160e01b600052602160045260246000fd5b61010083015260408601516001600160a01b031661012083015260608601516127a26101408401826001600160a01b03169052565b50608086015161016083015260a086015160c06101808401526127c96101a0840182612711565b915050612809602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b6000825161282d8184602087016126ed565b9190910192915050565b60006020828403121561284957600080fd5b6109848261252d565b6000600182016128645761286461248f565b5060010190565b818103818111156111ac576111ac61248f565b805169ffffffffffffffffffff8116811461253d57600080fd5b600080600080600060a086880312156128b057600080fd5b6128b98661287e565b94506020860151935060408601519250606086015191506128dc6080870161287e565b9050929550929590935056fea264697066735822122034d6076b22da7cecbf8a6b93581d263c4fcee103111e1a043ce67842daccaaa964736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d435740000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c33590000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f70000000000000000000000000000000000000000000000000000000000015180
-----Decoded View---------------
Arg [0] : _sweep (address): 0xB88a5Ac00917a02d82c7cd6CEBd73E2852d43574
Arg [1] : _base (address): 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359
Arg [2] : _sequencer (address): 0x0000000000000000000000000000000000000000
Arg [3] : _oracleBase (address): 0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7
Arg [4] : _oracleBaseUpdateFrequency (uint256): 86400
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000b88a5ac00917a02d82c7cd6cebd73e2852d43574
Arg [1] : 0000000000000000000000003c499c542cef5e3811e1192ce70d8cc03d5c3359
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000fe4a8cc5b5b2366c1b58bea3858e81843581b2f7
Arg [4] : 0000000000000000000000000000000000000000000000000000000000015180
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.