Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Cross-Chain Transactions
Loading...
Loading
Contract Name:
CircuitBreakerLib
Compiler Version
v0.7.1+commit.f4a555be
Optimization Enabled:
Yes with 9999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/Math.sol";
/**
* @title Circuit Breaker Library
* @notice Library for logic and functions related to circuit breakers.
*/
library CircuitBreakerLib {
using FixedPoint for uint256;
/**
* @notice Single-sided check for whether a lower or upper circuit breaker would trip in the given pool state.
* @dev Compute the current BPT price from the input parameters, and compare it to the given bound to determine
* whether the given post-operation pool state is within the circuit breaker bounds.
* @param virtualSupply - the post-operation totalSupply (including protocol fees, etc.)
* @param weight - the normalized weight of the token we are checking.
* @param balance - the post-operation token balance (including swap fees, etc.). It must be an 18-decimal
* floating point number, adjusted by the scaling factor of the token.
* @param boundBptPrice - the BPT price at the limit (lower or upper) of the allowed trading range.
* @param isLowerBound - true if the boundBptPrice represents the lower bound.
* @return - boolean flag for whether the breaker has been tripped.
*/
function hasCircuitBreakerTripped(
uint256 virtualSupply,
uint256 weight,
uint256 balance,
uint256 boundBptPrice,
bool isLowerBound
) internal pure returns (bool) {
// A bound price of 0 means that no breaker is set.
if (boundBptPrice == 0) {
return false;
}
// Round down for lower bound checks, up for upper bound checks
uint256 currentBptPrice = Math.div(Math.mul(virtualSupply, weight), balance, !isLowerBound);
return isLowerBound ? currentBptPrice < boundBptPrice : currentBptPrice > boundBptPrice;
}
/**
* @notice Convert a bound to a BPT price ratio
* @param bound - The bound percentage.
* @param weight - The current normalized token weight.
* @param isLowerBound - A flag indicating whether this is for a lower bound.
*/
function calcAdjustedBound(
uint256 bound,
uint256 weight,
bool isLowerBound
) external pure returns (uint256 boundRatio) {
// To be conservative and protect LPs, round up for the lower bound, and down for the upper bound.
boundRatio = (isLowerBound ? FixedPoint.powUp : FixedPoint.powDown)(bound, weight.complement());
}
/**
* @notice Convert a BPT price ratio to a BPT price bound
* @param boundRatio - The cached bound ratio
* @param bptPrice - The BPT price stored at the time the breaker was set.
* @param isLowerBound - A flag indicating whether this is for a lower bound.
*/
function calcBptPriceBoundary(
uint256 boundRatio,
uint256 bptPrice,
bool isLowerBound
) internal pure returns (uint256 boundBptPrice) {
// To be conservative and protect LPs, round up for the lower bound, and down for the upper bound.
boundBptPrice = (isLowerBound ? FixedPoint.mulUp : FixedPoint.mulDown)(bptPrice, boundRatio);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
// solhint-disable
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
* supported.
* Uses the default 'BAL' prefix for the error code
*/
function _require(bool condition, uint256 errorCode) pure {
if (!condition) _revert(errorCode);
}
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
* supported.
*/
function _require(
bool condition,
uint256 errorCode,
bytes3 prefix
) pure {
if (!condition) _revert(errorCode, prefix);
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
* Uses the default 'BAL' prefix for the error code
*/
function _revert(uint256 errorCode) pure {
_revert(errorCode, 0x42414c); // This is the raw byte representation of "BAL"
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
*/
function _revert(uint256 errorCode, bytes3 prefix) pure {
uint256 prefixUint = uint256(uint24(prefix));
// We're going to dynamically create a revert string based on the error code, with the following format:
// 'BAL#{errorCode}'
// where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
//
// We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
// number (8 to 16 bits) than the individual string characters.
//
// The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
// much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
// safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
assembly {
// First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
// range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
// the '0' character.
let units := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let tenths := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let hundreds := add(mod(errorCode, 10), 0x30)
// With the individual characters, we can now construct the full string.
// We first append the '#' character (0x23) to the prefix. In the case of 'BAL', it results in 0x42414c23 ('BAL#')
// Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the
// characters to it, each shifted by a multiple of 8.
// The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
// per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
// array).
let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint)))
let revertReason := shl(200, add(formattedPrefix, add(add(units, shl(8, tenths)), shl(16, hundreds))))
// We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
// message will have the following layout:
// [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]
// The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
// also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// The string length is fixed: 7 characters.
mstore(0x24, 7)
// Finally, the string itself is stored.
mstore(0x44, revertReason)
// Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
// the encoded message is therefore 4 + 32 + 32 + 32 = 100.
revert(0, 100)
}
}
library Errors {
// Math
uint256 internal constant ADD_OVERFLOW = 0;
uint256 internal constant SUB_OVERFLOW = 1;
uint256 internal constant SUB_UNDERFLOW = 2;
uint256 internal constant MUL_OVERFLOW = 3;
uint256 internal constant ZERO_DIVISION = 4;
uint256 internal constant DIV_INTERNAL = 5;
uint256 internal constant X_OUT_OF_BOUNDS = 6;
uint256 internal constant Y_OUT_OF_BOUNDS = 7;
uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
uint256 internal constant INVALID_EXPONENT = 9;
// Input
uint256 internal constant OUT_OF_BOUNDS = 100;
uint256 internal constant UNSORTED_ARRAY = 101;
uint256 internal constant UNSORTED_TOKENS = 102;
uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
uint256 internal constant ZERO_TOKEN = 104;
uint256 internal constant INSUFFICIENT_DATA = 105;
// Shared pools
uint256 internal constant MIN_TOKENS = 200;
uint256 internal constant MAX_TOKENS = 201;
uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
uint256 internal constant MINIMUM_BPT = 204;
uint256 internal constant CALLER_NOT_VAULT = 205;
uint256 internal constant UNINITIALIZED = 206;
uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
uint256 internal constant EXPIRED_PERMIT = 209;
uint256 internal constant NOT_TWO_TOKENS = 210;
uint256 internal constant DISABLED = 211;
// Pools
uint256 internal constant MIN_AMP = 300;
uint256 internal constant MAX_AMP = 301;
uint256 internal constant MIN_WEIGHT = 302;
uint256 internal constant MAX_STABLE_TOKENS = 303;
uint256 internal constant MAX_IN_RATIO = 304;
uint256 internal constant MAX_OUT_RATIO = 305;
uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
uint256 internal constant INVALID_TOKEN = 309;
uint256 internal constant UNHANDLED_JOIN_KIND = 310;
uint256 internal constant ZERO_INVARIANT = 311;
uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
uint256 internal constant ORACLE_INVALID_INDEX = 315;
uint256 internal constant ORACLE_BAD_SECS = 316;
uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;
uint256 internal constant AMP_ONGOING_UPDATE = 318;
uint256 internal constant AMP_RATE_TOO_HIGH = 319;
uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;
uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;
uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;
uint256 internal constant RELAYER_NOT_CONTRACT = 323;
uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;
uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;
uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;
uint256 internal constant SWAPS_DISABLED = 327;
uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;
uint256 internal constant PRICE_RATE_OVERFLOW = 329;
uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;
uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;
uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;
uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;
uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;
uint256 internal constant OUT_OF_TARGET_RANGE = 335;
uint256 internal constant UNHANDLED_EXIT_KIND = 336;
uint256 internal constant UNAUTHORIZED_EXIT = 337;
uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;
uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;
uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;
uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;
uint256 internal constant INVALID_INITIALIZATION = 342;
uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;
uint256 internal constant FEATURE_DISABLED = 344;
uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;
uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346;
uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347;
uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348;
uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349;
uint256 internal constant MAX_WEIGHT = 350;
uint256 internal constant UNAUTHORIZED_JOIN = 351;
uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352;
uint256 internal constant FRACTIONAL_TARGET = 353;
uint256 internal constant ADD_OR_REMOVE_BPT = 354;
uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355;
uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356;
uint256 internal constant MALICIOUS_QUERY_REVERT = 357;
uint256 internal constant JOINS_EXITS_DISABLED = 358;
// Lib
uint256 internal constant REENTRANCY = 400;
uint256 internal constant SENDER_NOT_ALLOWED = 401;
uint256 internal constant PAUSED = 402;
uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
uint256 internal constant INSUFFICIENT_BALANCE = 406;
uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;
uint256 internal constant CALLER_IS_NOT_OWNER = 426;
uint256 internal constant NEW_OWNER_IS_ZERO = 427;
uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;
uint256 internal constant CALL_TO_NON_CONTRACT = 429;
uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;
uint256 internal constant NOT_PAUSED = 431;
uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;
uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;
uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;
uint256 internal constant INVALID_OPERATION = 435;
uint256 internal constant CODEC_OVERFLOW = 436;
uint256 internal constant IN_RECOVERY_MODE = 437;
uint256 internal constant NOT_IN_RECOVERY_MODE = 438;
uint256 internal constant INDUCED_FAILURE = 439;
uint256 internal constant EXPIRED_SIGNATURE = 440;
uint256 internal constant MALFORMED_SIGNATURE = 441;
uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442;
uint256 internal constant UNHANDLED_FEE_TYPE = 443;
uint256 internal constant BURN_FROM_ZERO = 444;
// Vault
uint256 internal constant INVALID_POOL_ID = 500;
uint256 internal constant CALLER_NOT_POOL = 501;
uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
uint256 internal constant INVALID_SIGNATURE = 504;
uint256 internal constant EXIT_BELOW_MIN = 505;
uint256 internal constant JOIN_ABOVE_MAX = 506;
uint256 internal constant SWAP_LIMIT = 507;
uint256 internal constant SWAP_DEADLINE = 508;
uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
uint256 internal constant INSUFFICIENT_ETH = 516;
uint256 internal constant UNALLOCATED_ETH = 517;
uint256 internal constant ETH_TRANSFER = 518;
uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
uint256 internal constant TOKENS_MISMATCH = 520;
uint256 internal constant TOKEN_NOT_REGISTERED = 521;
uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
uint256 internal constant TOKENS_ALREADY_SET = 523;
uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
uint256 internal constant POOL_NO_TOKENS = 527;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;
// Fees
uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603;
// FeeSplitter
uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700;
// Misc
uint256 internal constant UNIMPLEMENTED = 998;
uint256 internal constant SHOULD_NOT_HAPPEN = 999;
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
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, Errors.ADD_OVERFLOW);
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
// Fixed Point addition is the same as regular checked addition
_require(b <= a, Errors.SUB_OVERFLOW);
uint256 c = a - b;
return c;
}
function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 product = a * b;
_require(a == 0 || product / a == b, Errors.MUL_OVERFLOW);
return product / ONE;
}
function mulUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
uint256 product = a * b;
_require(a == 0 || product / a == b, Errors.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, Errors.ZERO_DIVISION);
uint256 aInflated = a * ONE;
_require(a == 0 || aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow
return aInflated / b;
}
function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
_require(b != 0, Errors.ZERO_DIVISION);
uint256 aInflated = a * ONE;
_require(a == 0 || aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow
// The traditional divUp formula is:
// divUp(x, y) := (x + y - 1) / y
// To avoid intermediate overflow in the addition, we distribute the division and get:
// divUp(x, y) := (x - 1) / y + 1
// Note that this requires x != 0, 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: MIT
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
/* solhint-disable */
/**
* @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
*
* Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
* exponentiation and logarithm (where the base is Euler's number).
*
* @author Fernando Martinelli - @fernandomartinelli
* @author Sergio Yuhjtman - @sergioyuhjtman
* @author Daniel Fernandez - @dmf7z
*/
library LogExpMath {
// All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
// two numbers, and multiply by ONE when dividing them.
// All arguments and return values are 18 decimal fixed point numbers.
int256 constant ONE_18 = 1e18;
// Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
// case of ln36, 36 decimals.
int256 constant ONE_20 = 1e20;
int256 constant ONE_36 = 1e36;
// The domain of natural exponentiation is bound by the word size and number of decimals used.
//
// Because internally the result will be stored using 20 decimals, the largest possible result is
// (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
// The smallest possible result is 10^(-18), which makes largest negative argument
// ln(10^(-18)) = -41.446531673892822312.
// We use 130.0 and -41.0 to have some safety margin.
int256 constant MAX_NATURAL_EXPONENT = 130e18;
int256 constant MIN_NATURAL_EXPONENT = -41e18;
// Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
// 256 bit integer.
int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;
uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);
// 18 decimal constants
int256 constant x0 = 128000000000000000000; // 2ˆ7
int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
int256 constant x1 = 64000000000000000000; // 2ˆ6
int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)
// 20 decimal constants
int256 constant x2 = 3200000000000000000000; // 2ˆ5
int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
int256 constant x3 = 1600000000000000000000; // 2ˆ4
int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
int256 constant x4 = 800000000000000000000; // 2ˆ3
int256 constant a4 = 298095798704172827474000; // eˆ(x4)
int256 constant x5 = 400000000000000000000; // 2ˆ2
int256 constant a5 = 5459815003314423907810; // eˆ(x5)
int256 constant x6 = 200000000000000000000; // 2ˆ1
int256 constant a6 = 738905609893065022723; // eˆ(x6)
int256 constant x7 = 100000000000000000000; // 2ˆ0
int256 constant a7 = 271828182845904523536; // eˆ(x7)
int256 constant x8 = 50000000000000000000; // 2ˆ-1
int256 constant a8 = 164872127070012814685; // eˆ(x8)
int256 constant x9 = 25000000000000000000; // 2ˆ-2
int256 constant a9 = 128402541668774148407; // eˆ(x9)
int256 constant x10 = 12500000000000000000; // 2ˆ-3
int256 constant a10 = 113314845306682631683; // eˆ(x10)
int256 constant x11 = 6250000000000000000; // 2ˆ-4
int256 constant a11 = 106449445891785942956; // eˆ(x11)
/**
* @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
*
* Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
*/
function pow(uint256 x, uint256 y) internal pure returns (uint256) {
if (y == 0) {
// We solve the 0^0 indetermination by making it equal one.
return uint256(ONE_18);
}
if (x == 0) {
return 0;
}
// Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
// arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
// x^y = exp(y * ln(x)).
// The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
_require(x >> 255 == 0, Errors.X_OUT_OF_BOUNDS);
int256 x_int256 = int256(x);
// We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
// both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.
// This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
_require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);
int256 y_int256 = int256(y);
int256 logx_times_y;
if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
int256 ln_36_x = _ln_36(x_int256);
// ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
// bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
// multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
// (downscaled) last 18 decimals.
logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
} else {
logx_times_y = _ln(x_int256) * y_int256;
}
logx_times_y /= ONE_18;
// Finally, we compute exp(y * ln(x)) to arrive at x^y
_require(
MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
Errors.PRODUCT_OUT_OF_BOUNDS
);
return uint256(exp(logx_times_y));
}
/**
* @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
*
* Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
*/
function exp(int256 x) internal pure returns (int256) {
_require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);
if (x < 0) {
// We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
// fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
// Fixed point division requires multiplying by ONE_18.
return ((ONE_18 * ONE_18) / exp(-x));
}
// First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
// where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
// because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
// decomposition.
// At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
// decomposition, which will be lower than the smallest x_n.
// exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
// We mutate x by subtracting x_n, making it the remainder of the decomposition.
// The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
// intermediate overflows. Instead we store them as plain integers, with 0 decimals.
// Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
// decomposition.
// For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
// it and compute the accumulated product.
int256 firstAN;
if (x >= x0) {
x -= x0;
firstAN = a0;
} else if (x >= x1) {
x -= x1;
firstAN = a1;
} else {
firstAN = 1; // One with no decimal places
}
// We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
// smaller terms.
x *= 100;
// `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
// one. Recall that fixed point multiplication requires dividing by ONE_20.
int256 product = ONE_20;
if (x >= x2) {
x -= x2;
product = (product * a2) / ONE_20;
}
if (x >= x3) {
x -= x3;
product = (product * a3) / ONE_20;
}
if (x >= x4) {
x -= x4;
product = (product * a4) / ONE_20;
}
if (x >= x5) {
x -= x5;
product = (product * a5) / ONE_20;
}
if (x >= x6) {
x -= x6;
product = (product * a6) / ONE_20;
}
if (x >= x7) {
x -= x7;
product = (product * a7) / ONE_20;
}
if (x >= x8) {
x -= x8;
product = (product * a8) / ONE_20;
}
if (x >= x9) {
x -= x9;
product = (product * a9) / ONE_20;
}
// x10 and x11 are unnecessary here since we have high enough precision already.
// Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
// expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).
int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
int256 term; // Each term in the sum, where the nth term is (x^n / n!).
// The first term is simply x.
term = x;
seriesSum += term;
// Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
// multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.
term = ((term * x) / ONE_20) / 2;
seriesSum += term;
term = ((term * x) / ONE_20) / 3;
seriesSum += term;
term = ((term * x) / ONE_20) / 4;
seriesSum += term;
term = ((term * x) / ONE_20) / 5;
seriesSum += term;
term = ((term * x) / ONE_20) / 6;
seriesSum += term;
term = ((term * x) / ONE_20) / 7;
seriesSum += term;
term = ((term * x) / ONE_20) / 8;
seriesSum += term;
term = ((term * x) / ONE_20) / 9;
seriesSum += term;
term = ((term * x) / ONE_20) / 10;
seriesSum += term;
term = ((term * x) / ONE_20) / 11;
seriesSum += term;
term = ((term * x) / ONE_20) / 12;
seriesSum += term;
// 12 Taylor terms are sufficient for 18 decimal precision.
// We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
// approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
// all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
// and then drop two digits to return an 18 decimal value.
return (((product * seriesSum) / ONE_20) * firstAN) / 100;
}
/**
* @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.
*/
function log(int256 arg, int256 base) internal pure returns (int256) {
// This performs a simple base change: log(arg, base) = ln(arg) / ln(base).
// Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by
// upscaling.
int256 logBase;
if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {
logBase = _ln_36(base);
} else {
logBase = _ln(base) * ONE_18;
}
int256 logArg;
if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {
logArg = _ln_36(arg);
} else {
logArg = _ln(arg) * ONE_18;
}
// When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places
return (logArg * ONE_18) / logBase;
}
/**
* @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function ln(int256 a) internal pure returns (int256) {
// The real natural logarithm is not defined for negative numbers or zero.
_require(a > 0, Errors.OUT_OF_BOUNDS);
if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
return _ln_36(a) / ONE_18;
} else {
return _ln(a);
}
}
/**
* @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function _ln(int256 a) private pure returns (int256) {
if (a < ONE_18) {
// Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
// than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
// Fixed point division requires multiplying by ONE_18.
return (-_ln((ONE_18 * ONE_18) / a));
}
// First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
// we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
// ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
// be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
// At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
// decomposition, which will be lower than the smallest a_n.
// ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
// We mutate a by subtracting a_n, making it the remainder of the decomposition.
// For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
// numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
// ONE_18 to convert them to fixed point.
// For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
// by it and compute the accumulated sum.
int256 sum = 0;
if (a >= a0 * ONE_18) {
a /= a0; // Integer, not fixed point division
sum += x0;
}
if (a >= a1 * ONE_18) {
a /= a1; // Integer, not fixed point division
sum += x1;
}
// All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
sum *= 100;
a *= 100;
// Because further a_n are 20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.
if (a >= a2) {
a = (a * ONE_20) / a2;
sum += x2;
}
if (a >= a3) {
a = (a * ONE_20) / a3;
sum += x3;
}
if (a >= a4) {
a = (a * ONE_20) / a4;
sum += x4;
}
if (a >= a5) {
a = (a * ONE_20) / a5;
sum += x5;
}
if (a >= a6) {
a = (a * ONE_20) / a6;
sum += x6;
}
if (a >= a7) {
a = (a * ONE_20) / a7;
sum += x7;
}
if (a >= a8) {
a = (a * ONE_20) / a8;
sum += x8;
}
if (a >= a9) {
a = (a * ONE_20) / a9;
sum += x9;
}
if (a >= a10) {
a = (a * ONE_20) / a10;
sum += x10;
}
if (a >= a11) {
a = (a * ONE_20) / a11;
sum += x11;
}
// a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
// that converges rapidly for values of `a` close to one - the same one used in ln_36.
// Let z = (a - 1) / (a + 1).
// ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
// division by ONE_20.
int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
int256 z_squared = (z * z) / ONE_20;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_20;
seriesSum += num / 3;
num = (num * z_squared) / ONE_20;
seriesSum += num / 5;
num = (num * z_squared) / ONE_20;
seriesSum += num / 7;
num = (num * z_squared) / ONE_20;
seriesSum += num / 9;
num = (num * z_squared) / ONE_20;
seriesSum += num / 11;
// 6 Taylor terms are sufficient for 36 decimal precision.
// Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
seriesSum *= 2;
// We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
// with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
// value.
return (sum + seriesSum) / 100;
}
/**
* @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
* for x close to one.
*
* Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
*/
function _ln_36(int256 x) private pure returns (int256) {
// Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
// worthwhile.
// First, we transform x to a 36 digit fixed point value.
x *= ONE_18;
// We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
// ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
// division by ONE_36.
int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
int256 z_squared = (z * z) / ONE_36;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_36;
seriesSum += num / 3;
num = (num * z_squared) / ONE_36;
seriesSum += num / 5;
num = (num * z_squared) / ONE_36;
seriesSum += num / 7;
num = (num * z_squared) / ONE_36;
seriesSum += num / 9;
num = (num * z_squared) / ONE_36;
seriesSum += num / 11;
num = (num * z_squared) / ONE_36;
seriesSum += num / 13;
num = (num * z_squared) / ONE_36;
seriesSum += num / 15;
// 8 Taylor terms are sufficient for 36 decimal precision.
// All that remains is multiplying by 2 (non fixed point).
return seriesSum * 2;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow checks.
* Adapted from OpenZeppelin's SafeMath library.
*/
library Math {
// 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, Errors.ADD_OVERFLOW);
return c;
}
/**
* @dev Returns the addition of two signed integers, reverting on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
_require((b >= 0 && c >= a) || (b < 0 && c < a), Errors.ADD_OVERFLOW);
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b <= a, Errors.SUB_OVERFLOW);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
_require((b >= 0 && c <= a) || (b < 0 && c > a), Errors.SUB_OVERFLOW);
return c;
}
/**
* @dev Returns the largest of two numbers of 256 bits.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256 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, Errors.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, Errors.ZERO_DIVISION);
return a / b;
}
function divUp(uint256 a, uint256 b) internal pure returns (uint256 result) {
_require(b != 0, Errors.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)))
}
}
}{
"optimizer": {
"enabled": true,
"runs": 9999
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"bound","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"bool","name":"isLowerBound","type":"bool"}],"name":"calcAdjustedBound","outputs":[{"internalType":"uint256","name":"boundRatio","type":"uint256"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
610e4f610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063f4d8cb7c1461003a575b600080fd5b6100656004803603606081101561005057600080fd5b50803590602081013590604001351515610077565b60408051918252519081900360200190f35b600061009f84610086856100a7565b84610093576100b9610097565b6101735b63ffffffff16565b949350505050565b670de0b6b3a764000081810391100290565b6000670de0b6b3a76400008214156100d257508161016d565b671bc16d674ec800008214156100f3576100ec83846101f9565b905061016d565b673782dace9d90000082141561012357600061010f84856101f9565b905061011b81826101f9565b91505061016d565b600061012f848461022f565b905060006101496101428361271061034f565b6001610387565b90508082101561015e5760009250505061016d565b61016882826103a0565b925050505b92915050565b6000670de0b6b3a764000082141561018c57508161016d565b671bc16d674ec800008214156101a6576100ec838461034f565b673782dace9d9000008214156101ce5760006101c2848561034f565b905061011b818261034f565b60006101da848461022f565b905060006101ed6101428361271061034f565b90506101688282610387565b600082820261021d84158061021657508385838161021357fe5b04145b60036103b6565b670de0b6b3a764000090049392505050565b6000816102455750670de0b6b3a764000061016d565b826102525750600061016d565b61026260ff84901c1560066103b6565b82610288770bce5086492111aea88f4bb1ca6bcf584181ea8059f76532841060076103b6565b826000670c7d713b49da0000831380156102a95750670f43fc2c04ee000083125b156102e05760006102b9846103c8565b9050670de0b6b3a764000080820784020583670de0b6b3a7640000830502019150506102ee565b816102ea84610501565b0290505b670de0b6b3a7640000900561033c7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc00008212801590610335575068070c1cc73b00c800008213155b60086103b6565b610345816108a1565b9695505050505050565b600082820261036984158061021657508385838161021357fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b600082820161039984821015836103b6565b9392505050565b60006103b08383111560016103b6565b50900390565b816103c4576103c481610d71565b5050565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401907fffffffffffffffffffffffffffffffffff3f68318436f8ea4cb460f0000000008501028161041457fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f820581019050806002029450505050505b919050565b6000670de0b6b3a764000082121561053e57610534826ec097ce7bc90715b34b9f10000000008161052e57fe5b05610501565b60000390506104fc565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261058f57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126105c7576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261060f576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a700831261064a576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261068157693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126106b857690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126106ed5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261071857680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261074d576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312610782576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126107b6576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac83126107ea576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161080d57fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b60006108e67ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc000083121580156108df575068070c1cc73b00c800008313155b60096103b6565b600082121561091a576108fb826000036108a1565b6ec097ce7bc90715b34b9f10000000008161091257fe5b0590506104fc565b60006806f05b59d3b2000000831261097057507ffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4e00000090910190770195e54c5dd42177f53a27172fa9ec6302628270000000006109bc565b6803782dace9d900000083126109b857507ffffffffffffffffffffffffffffffffffffffffffffffffc87d2531627000000909101906b1425982cf597cd205cef73806109bc565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412610a22577fffffffffffffffffffffffffffffffffffffffffffffff5287143a539e0000009093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412610a74577fffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf0000009093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412610ac4577fffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e78000009093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412610b14577fffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c000009093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412610b63577ffffffffffffffffffffffffffffffffffffffffffffffff5287143a539e000009093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412610bb2577ffffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf000009093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412610c01577ffffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e7800009093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412610c50577ffffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c00009093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b610d9b817f42414c0000000000000000000000000000000000000000000000000000000000610d9e565b50565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fdfea2646970667358221220cb195cdbf9e262e4f4e9a4c4faf038de3b2317bcba20577205894269334cae4f64736f6c63430007010033
Deployed Bytecode
0x737ba29fe8e83dd6097a7298075c4affdbda3121cc30146080604052600436106100355760003560e01c8063f4d8cb7c1461003a575b600080fd5b6100656004803603606081101561005057600080fd5b50803590602081013590604001351515610077565b60408051918252519081900360200190f35b600061009f84610086856100a7565b84610093576100b9610097565b6101735b63ffffffff16565b949350505050565b670de0b6b3a764000081810391100290565b6000670de0b6b3a76400008214156100d257508161016d565b671bc16d674ec800008214156100f3576100ec83846101f9565b905061016d565b673782dace9d90000082141561012357600061010f84856101f9565b905061011b81826101f9565b91505061016d565b600061012f848461022f565b905060006101496101428361271061034f565b6001610387565b90508082101561015e5760009250505061016d565b61016882826103a0565b925050505b92915050565b6000670de0b6b3a764000082141561018c57508161016d565b671bc16d674ec800008214156101a6576100ec838461034f565b673782dace9d9000008214156101ce5760006101c2848561034f565b905061011b818261034f565b60006101da848461022f565b905060006101ed6101428361271061034f565b90506101688282610387565b600082820261021d84158061021657508385838161021357fe5b04145b60036103b6565b670de0b6b3a764000090049392505050565b6000816102455750670de0b6b3a764000061016d565b826102525750600061016d565b61026260ff84901c1560066103b6565b82610288770bce5086492111aea88f4bb1ca6bcf584181ea8059f76532841060076103b6565b826000670c7d713b49da0000831380156102a95750670f43fc2c04ee000083125b156102e05760006102b9846103c8565b9050670de0b6b3a764000080820784020583670de0b6b3a7640000830502019150506102ee565b816102ea84610501565b0290505b670de0b6b3a7640000900561033c7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc00008212801590610335575068070c1cc73b00c800008213155b60086103b6565b610345816108a1565b9695505050505050565b600082820261036984158061021657508385838161021357fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b600082820161039984821015836103b6565b9392505050565b60006103b08383111560016103b6565b50900390565b816103c4576103c481610d71565b5050565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401907fffffffffffffffffffffffffffffffffff3f68318436f8ea4cb460f0000000008501028161041457fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f820581019050806002029450505050505b919050565b6000670de0b6b3a764000082121561053e57610534826ec097ce7bc90715b34b9f10000000008161052e57fe5b05610501565b60000390506104fc565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261058f57770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e00000083126105c7576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff0084000831261060f576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a700831261064a576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261068157693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e283126106b857690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126106ed5768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb41746121110831261071857680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d831261074d576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312610782576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b28660383126107b6576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac83126107ea576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d63100000808603028161080d57fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b60006108e67ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc000083121580156108df575068070c1cc73b00c800008313155b60096103b6565b600082121561091a576108fb826000036108a1565b6ec097ce7bc90715b34b9f10000000008161091257fe5b0590506104fc565b60006806f05b59d3b2000000831261097057507ffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4e00000090910190770195e54c5dd42177f53a27172fa9ec6302628270000000006109bc565b6803782dace9d900000083126109b857507ffffffffffffffffffffffffffffffffffffffffffffffffc87d2531627000000909101906b1425982cf597cd205cef73806109bc565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412610a22577fffffffffffffffffffffffffffffffffffffffffffffff5287143a539e0000009093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412610a74577fffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf0000009093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412610ac4577fffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e78000009093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412610b14577fffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c000009093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412610b63577ffffffffffffffffffffffffffffffffffffffffffffffff5287143a539e000009093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412610bb2577ffffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf000009093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412610c01577ffffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e7800009093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412610c50577ffffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c00009093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b610d9b817f42414c0000000000000000000000000000000000000000000000000000000000610d9e565b50565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fdfea2646970667358221220cb195cdbf9e262e4f4e9a4c4faf038de3b2317bcba20577205894269334cae4f64736f6c63430007010033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.