Source Code
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ExternalWeightedMath
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-interfaces/contracts/pool-weighted/IExternalWeightedMath.sol";
import "@balancer-labs/v2-pool-utils/contracts/lib/BasePoolMath.sol";
import "./lib/WeightedExitsLib.sol";
import "./lib/WeightedJoinsLib.sol";
import "./WeightedMath.sol";
/**
* @notice A contract-wrapper for Weighted Math, Joins and Exits.
* @dev Use this contract as an external replacement for WeightedMath, WeightedJoinsLib and WeightedExitsLib libraries.
*/
contract ExternalWeightedMath is IExternalWeightedMath {
function calculateInvariant(uint256[] memory normalizedWeights, uint256[] memory balances)
external
pure
override
returns (uint256)
{
return WeightedMath._calculateInvariant(normalizedWeights, balances);
}
function calcOutGivenIn(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountIn
) external pure override returns (uint256) {
return WeightedMath._calcOutGivenIn(balanceIn, weightIn, balanceOut, weightOut, amountIn);
}
function calcInGivenOut(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountOut
) external pure override returns (uint256) {
return WeightedMath._calcInGivenOut(balanceIn, weightIn, balanceOut, weightOut, amountOut);
}
function calcBptOutGivenExactTokensIn(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcBptOutGivenExactTokensIn(
balances,
normalizedWeights,
amountsIn,
bptTotalSupply,
swapFeePercentage
);
}
function calcBptOutGivenExactTokenIn(
uint256 balance,
uint256 normalizedWeight,
uint256 amountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcBptOutGivenExactTokenIn(
balance,
normalizedWeight,
amountIn,
bptTotalSupply,
swapFeePercentage
);
}
function calcTokenInGivenExactBptOut(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcTokenInGivenExactBptOut(
balance,
normalizedWeight,
bptAmountOut,
bptTotalSupply,
swapFeePercentage
);
}
function calcAllTokensInGivenExactBptOut(
uint256[] memory balances,
uint256 bptAmountOut,
uint256 totalBPT
) external pure override returns (uint256[] memory) {
return BasePoolMath.computeProportionalAmountsIn(balances, totalBPT, bptAmountOut);
}
function calcBptInGivenExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcBptInGivenExactTokensOut(
balances,
normalizedWeights,
amountsOut,
bptTotalSupply,
swapFeePercentage
);
}
function calcBptInGivenExactTokenOut(
uint256 balance,
uint256 normalizedWeight,
uint256 amountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcBptInGivenExactTokenOut(
balance,
normalizedWeight,
amountOut,
bptTotalSupply,
swapFeePercentage
);
}
function calcTokenOutGivenExactBptIn(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure override returns (uint256) {
return
WeightedMath._calcTokenOutGivenExactBptIn(
balance,
normalizedWeight,
bptAmountIn,
bptTotalSupply,
swapFeePercentage
);
}
function calcTokensOutGivenExactBptIn(
uint256[] memory balances,
uint256 bptAmountIn,
uint256 totalBPT
) external pure override returns (uint256[] memory) {
return BasePoolMath.computeProportionalAmountsOut(balances, totalBPT, bptAmountIn);
}
function calcBptOutAddToken(uint256 totalSupply, uint256 normalizedWeight)
external
pure
override
returns (uint256)
{
return WeightedMath._calcBptOutAddToken(totalSupply, normalizedWeight);
}
function joinExactTokensInForBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure override returns (uint256, uint256[] memory) {
return
WeightedJoinsLib.joinExactTokensInForBPTOut(
balances,
normalizedWeights,
scalingFactors,
totalSupply,
swapFeePercentage,
userData
);
}
function joinTokenInForExactBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure override returns (uint256, uint256[] memory) {
return
WeightedJoinsLib.joinTokenInForExactBPTOut(
balances,
normalizedWeights,
totalSupply,
swapFeePercentage,
userData
);
}
function joinAllTokensInForExactBPTOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) external pure override returns (uint256 bptAmountOut, uint256[] memory amountsIn) {
return WeightedJoinsLib.joinAllTokensInForExactBPTOut(balances, totalSupply, userData);
}
function exitExactBPTInForTokenOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure override returns (uint256, uint256[] memory) {
return
WeightedExitsLib.exitExactBPTInForTokenOut(
balances,
normalizedWeights,
totalSupply,
swapFeePercentage,
userData
);
}
function exitExactBPTInForTokensOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) external pure override returns (uint256 bptAmountIn, uint256[] memory amountsOut) {
return WeightedExitsLib.exitExactBPTInForTokensOut(balances, totalSupply, userData);
}
function exitBPTInForExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure override returns (uint256, uint256[] memory) {
return
WeightedExitsLib.exitBPTInForExactTokensOut(
balances,
normalizedWeights,
scalingFactors,
totalSupply,
swapFeePercentage,
userData
);
}
}// 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;
/**
* @notice Interface for ExternalWeightedMath, a contract-wrapper for Weighted Math, Joins and Exits.
*/
interface IExternalWeightedMath {
/**
* @dev See `WeightedMath._calculateInvariant`.
*/
function calculateInvariant(uint256[] memory normalizedWeights, uint256[] memory balances)
external
pure
returns (uint256);
/**
* @dev See `WeightedMath._calcOutGivenIn`.
*/
function calcOutGivenIn(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountIn
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcInGivenOut`.
*/
function calcInGivenOut(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountOut
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcBptOutGivenExactTokensIn`.
*/
function calcBptOutGivenExactTokensIn(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcBptOutGivenExactTokenIn`.
*/
function calcBptOutGivenExactTokenIn(
uint256 balance,
uint256 normalizedWeight,
uint256 amountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcTokenInGivenExactBptOut`.
*/
function calcTokenInGivenExactBptOut(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcAllTokensInGivenExactBptOut`.
*/
function calcAllTokensInGivenExactBptOut(
uint256[] memory balances,
uint256 bptAmountOut,
uint256 totalBPT
) external pure returns (uint256[] memory);
/**
* @dev See `WeightedMath._calcBptInGivenExactTokensOut`.
*/
function calcBptInGivenExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcBptInGivenExactTokenOut`.
*/
function calcBptInGivenExactTokenOut(
uint256 balance,
uint256 normalizedWeight,
uint256 amountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcTokenOutGivenExactBptIn`.
*/
function calcTokenOutGivenExactBptIn(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) external pure returns (uint256);
/**
* @dev See `WeightedMath._calcTokensOutGivenExactBptIn`.
*/
function calcTokensOutGivenExactBptIn(
uint256[] memory balances,
uint256 bptAmountIn,
uint256 totalBPT
) external pure returns (uint256[] memory);
/**
* @dev See `WeightedMath._calcBptOutAddToken`.
*/
function calcBptOutAddToken(uint256 totalSupply, uint256 normalizedWeight) external pure returns (uint256);
/**
* @dev See `WeightedJoinsLib.joinExactTokensInForBPTOut`.
*/
function joinExactTokensInForBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure returns (uint256, uint256[] memory);
/**
* @dev See `WeightedJoinsLib.joinTokenInForExactBPTOut`.
*/
function joinTokenInForExactBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure returns (uint256, uint256[] memory);
/**
* @dev See `WeightedJoinsLib.joinAllTokensInForExactBPTOut`.
*/
function joinAllTokensInForExactBPTOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) external pure returns (uint256 bptAmountOut, uint256[] memory amountsIn);
/**
* @dev See `WeightedExitsLib.exitExactBPTInForTokenOut`.
*/
function exitExactBPTInForTokenOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure returns (uint256, uint256[] memory);
/**
* @dev See `WeightedExitsLib.exitExactBPTInForTokensOut`.
*/
function exitExactBPTInForTokensOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) external pure returns (uint256 bptAmountIn, uint256[] memory amountsOut);
/**
* @dev See `WeightedExitsLib.exitBPTInForExactTokensOut`.
*/
function exitBPTInForExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) external pure returns (uint256, uint256[] memory);
}// 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;
import "../solidity-utils/openzeppelin/IERC20.sol";
library WeightedPoolUserData {
// In order to preserve backwards compatibility, make sure new join and exit kinds are added at the end of the enum.
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, EXACT_BPT_IN_FOR_TOKENS_OUT, BPT_IN_FOR_EXACT_TOKENS_OUT }
function joinKind(bytes memory self) internal pure returns (JoinKind) {
return abi.decode(self, (JoinKind));
}
function exitKind(bytes memory self) internal pure returns (ExitKind) {
return abi.decode(self, (ExitKind));
}
// Joins
function initialAmountsIn(bytes memory self) internal pure returns (uint256[] memory amountsIn) {
(, amountsIn) = abi.decode(self, (JoinKind, uint256[]));
}
function exactTokensInForBptOut(bytes memory self)
internal
pure
returns (uint256[] memory amountsIn, uint256 minBPTAmountOut)
{
(, amountsIn, minBPTAmountOut) = abi.decode(self, (JoinKind, uint256[], uint256));
}
function tokenInForExactBptOut(bytes memory self) internal pure returns (uint256 bptAmountOut, uint256 tokenIndex) {
(, bptAmountOut, tokenIndex) = abi.decode(self, (JoinKind, uint256, uint256));
}
function allTokensInForExactBptOut(bytes memory self) internal pure returns (uint256 bptAmountOut) {
(, bptAmountOut) = abi.decode(self, (JoinKind, uint256));
}
// Exits
function exactBptInForTokenOut(bytes memory self) internal pure returns (uint256 bptAmountIn, uint256 tokenIndex) {
(, bptAmountIn, tokenIndex) = abi.decode(self, (ExitKind, uint256, uint256));
}
function exactBptInForTokensOut(bytes memory self) internal pure returns (uint256 bptAmountIn) {
(, bptAmountIn) = abi.decode(self, (ExitKind, uint256));
}
function bptInForExactTokensOut(bytes memory self)
internal
pure
returns (uint256[] memory amountsOut, uint256 maxBPTAmountIn)
{
(, amountsOut, maxBPTAmountIn) = abi.decode(self, (ExitKind, uint256[], uint256));
}
}// 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: MIT
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @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);
}// 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;
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
library BasePoolMath {
using FixedPoint for uint256;
function computeProportionalAmountsIn(
uint256[] memory balances,
uint256 bptTotalSupply,
uint256 bptAmountOut
) internal pure returns (uint256[] memory amountsIn) {
/************************************************************************************
// computeProportionalAmountsIn //
// (per token) //
// aI = amountIn / bptOut \ //
// b = balance aI = b * | ----------------- | //
// bptOut = bptAmountOut \ bptTotalSupply / //
// bpt = bptTotalSupply //
************************************************************************************/
// Since we're computing amounts in, we round up overall. This means rounding up on both the
// multiplication and division.
uint256 bptRatio = bptAmountOut.divUp(bptTotalSupply);
amountsIn = new uint256[](balances.length);
for (uint256 i = 0; i < balances.length; i++) {
amountsIn[i] = balances[i].mulUp(bptRatio);
}
}
function computeProportionalAmountsOut(
uint256[] memory balances,
uint256 bptTotalSupply,
uint256 bptAmountIn
) internal pure returns (uint256[] memory amountsOut) {
/**********************************************************************************************
// computeProportionalAmountsOut //
// (per token) //
// aO = tokenAmountOut / bptIn \ //
// b = tokenBalance a0 = b * | --------------------- | //
// bptIn = bptAmountIn \ bptTotalSupply / //
// bpt = bptTotalSupply //
**********************************************************************************************/
// Since we're computing an amount out, we round down overall. This means rounding down on both the
// multiplication and division.
uint256 bptRatio = bptAmountIn.divDown(bptTotalSupply);
amountsOut = new uint256[](balances.length);
for (uint256 i = 0; i < balances.length; i++) {
amountsOut[i] = balances[i].mulDown(bptRatio);
}
}
}// 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/openzeppelin/IERC20.sol";
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
library InputHelpers {
function ensureInputLengthMatch(uint256 a, uint256 b) internal pure {
_require(a == b, Errors.INPUT_LENGTH_MISMATCH);
}
function ensureInputLengthMatch(
uint256 a,
uint256 b,
uint256 c
) internal pure {
_require(a == b && b == c, Errors.INPUT_LENGTH_MISMATCH);
}
function ensureArrayIsSorted(IERC20[] memory array) internal pure {
address[] memory addressArray;
// solhint-disable-next-line no-inline-assembly
assembly {
addressArray := array
}
ensureArrayIsSorted(addressArray);
}
function ensureArrayIsSorted(address[] memory array) internal pure {
if (array.length < 2) {
return;
}
address previous = array[0];
for (uint256 i = 1; i < array.length; ++i) {
address current = array[i];
_require(previous < current, Errors.UNSORTED_ARRAY);
previous = current;
}
}
}// 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 "../math/FixedPoint.sol";
import "../math/Math.sol";
import "../openzeppelin/ERC20.sol";
import "./InputHelpers.sol";
// solhint-disable
// To simplify Pool logic, all token balances and amounts are normalized to behave as if the token had 18 decimals.
// e.g. When comparing DAI (18 decimals) and USDC (6 decimals), 1 USDC and 1 DAI would both be represented as 1e18,
// whereas without scaling 1 USDC would be represented as 1e6.
// This allows us to not consider differences in token decimals in the internal Pool maths, simplifying it greatly.
// Single Value
/**
* @dev Applies `scalingFactor` to `amount`, resulting in a larger or equal value depending on whether it needed
* scaling or not.
*/
function _upscale(uint256 amount, uint256 scalingFactor) pure returns (uint256) {
// Upscale rounding wouldn't necessarily always go in the same direction: in a swap for example the balance of
// token in should be rounded up, and that of token out rounded down. This is the only place where we round in
// the same direction for all amounts, as the impact of this rounding is expected to be minimal.
return FixedPoint.mulDown(amount, scalingFactor);
}
/**
* @dev Reverses the `scalingFactor` applied to `amount`, resulting in a smaller or equal value depending on
* whether it needed scaling or not. The result is rounded down.
*/
function _downscaleDown(uint256 amount, uint256 scalingFactor) pure returns (uint256) {
return FixedPoint.divDown(amount, scalingFactor);
}
/**
* @dev Reverses the `scalingFactor` applied to `amount`, resulting in a smaller or equal value depending on
* whether it needed scaling or not. The result is rounded up.
*/
function _downscaleUp(uint256 amount, uint256 scalingFactor) pure returns (uint256) {
return FixedPoint.divUp(amount, scalingFactor);
}
// Array
/**
* @dev Same as `_upscale`, but for an entire array. This function does not return anything, but instead *mutates*
* the `amounts` array.
*/
function _upscaleArray(uint256[] memory amounts, uint256[] memory scalingFactors) pure {
uint256 length = amounts.length;
InputHelpers.ensureInputLengthMatch(length, scalingFactors.length);
for (uint256 i = 0; i < length; ++i) {
amounts[i] = FixedPoint.mulDown(amounts[i], scalingFactors[i]);
}
}
/**
* @dev Same as `_downscaleDown`, but for an entire array. This function does not return anything, but instead
* *mutates* the `amounts` array.
*/
function _downscaleDownArray(uint256[] memory amounts, uint256[] memory scalingFactors) pure {
uint256 length = amounts.length;
InputHelpers.ensureInputLengthMatch(length, scalingFactors.length);
for (uint256 i = 0; i < length; ++i) {
amounts[i] = FixedPoint.divDown(amounts[i], scalingFactors[i]);
}
}
/**
* @dev Same as `_downscaleUp`, but for an entire array. This function does not return anything, but instead
* *mutates* the `amounts` array.
*/
function _downscaleUpArray(uint256[] memory amounts, uint256[] memory scalingFactors) pure {
uint256 length = amounts.length;
InputHelpers.ensureInputLengthMatch(length, scalingFactors.length);
for (uint256 i = 0; i < length; ++i) {
amounts[i] = FixedPoint.divUp(amounts[i], scalingFactors[i]);
}
}
function _computeScalingFactor(IERC20 token) view returns (uint256) {
// Tokens that don't implement the `decimals` method are not supported.
uint256 tokenDecimals = ERC20(address(token)).decimals();
// Tokens with more than 18 decimals are not supported.
uint256 decimalsDifference = Math.sub(18, tokenDecimals);
return FixedPoint.ONE * 10**decimalsDifference;
}// 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)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/openzeppelin/IERC20.sol";
import "./SafeMath.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is IERC20 {
using SafeMath for uint256;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}. The total supply should only be read using this function
*
* Can be overridden by derived contracts to store the total supply in a different way (e.g. packed with other
* storage values).
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev Sets a new value for the total supply. It should only be set using this function.
*
* * Can be overridden by derived contracts to store the total supply in a different way (e.g. packed with other
* storage values).
*/
function _setTotalSupply(uint256 value) internal virtual {
_totalSupply = value;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(
sender,
msg.sender,
_allowances[sender][msg.sender].sub(amount, Errors.ERC20_TRANSFER_EXCEEDS_ALLOWANCE)
);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(
msg.sender,
spender,
_allowances[msg.sender][spender].sub(subtractedValue, Errors.ERC20_DECREASED_ALLOWANCE_BELOW_ZERO)
);
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
_require(sender != address(0), Errors.ERC20_TRANSFER_FROM_ZERO_ADDRESS);
_require(recipient != address(0), Errors.ERC20_TRANSFER_TO_ZERO_ADDRESS);
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, Errors.ERC20_TRANSFER_EXCEEDS_BALANCE);
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), account, amount);
_setTotalSupply(totalSupply().add(amount));
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
_require(account != address(0), Errors.ERC20_BURN_FROM_ZERO_ADDRESS);
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, Errors.ERC20_BURN_EXCEEDS_BALANCE);
_setTotalSupply(totalSupply().sub(amount));
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Sets {decimals} to a value other than the default one of 18.
*
* WARNING: This function should only be called from the constructor. Most
* applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does.
*/
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {
// solhint-disable-previous-line no-empty-blocks
}
}// 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.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot 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 subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, Errors.SUB_OVERFLOW);
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
uint256 errorCode
) internal pure returns (uint256) {
_require(b <= a, errorCode);
uint256 c = a - b;
return c;
}
}// 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/pool-weighted/WeightedPoolUserData.sol";
import "@balancer-labs/v2-pool-utils/contracts/lib/BasePoolMath.sol";
import "@balancer-labs/v2-solidity-utils/contracts/helpers/ScalingHelpers.sol";
import "../WeightedMath.sol";
library WeightedExitsLib {
using WeightedPoolUserData for bytes;
function exitExactBPTInForTokenOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) internal pure returns (uint256, uint256[] memory) {
(uint256 bptAmountIn, uint256 tokenIndex) = userData.exactBptInForTokenOut();
// Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`.
_require(tokenIndex < balances.length, Errors.OUT_OF_BOUNDS);
uint256 amountOut = WeightedMath._calcTokenOutGivenExactBptIn(
balances[tokenIndex],
normalizedWeights[tokenIndex],
bptAmountIn,
totalSupply,
swapFeePercentage
);
// This is an exceptional situation in which the fee is charged on a token out instead of a token in.
// We exit in a single token, so we initialize amountsOut with zeros
uint256[] memory amountsOut = new uint256[](balances.length);
// And then assign the result to the selected token
amountsOut[tokenIndex] = amountOut;
return (bptAmountIn, amountsOut);
}
function exitExactBPTInForTokensOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) internal pure returns (uint256 bptAmountIn, uint256[] memory amountsOut) {
bptAmountIn = userData.exactBptInForTokensOut();
// Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`.
amountsOut = BasePoolMath.computeProportionalAmountsOut(balances, totalSupply, bptAmountIn);
}
function exitBPTInForExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) internal pure returns (uint256, uint256[] memory) {
(uint256[] memory amountsOut, uint256 maxBPTAmountIn) = userData.bptInForExactTokensOut();
InputHelpers.ensureInputLengthMatch(amountsOut.length, balances.length);
_upscaleArray(amountsOut, scalingFactors);
// This is an exceptional situation in which the fee is charged on a token out instead of a token in.
uint256 bptAmountIn = WeightedMath._calcBptInGivenExactTokensOut(
balances,
normalizedWeights,
amountsOut,
totalSupply,
swapFeePercentage
);
_require(bptAmountIn <= maxBPTAmountIn, Errors.BPT_IN_MAX_AMOUNT);
return (bptAmountIn, amountsOut);
}
}// 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/pool-weighted/WeightedPoolUserData.sol";
import "@balancer-labs/v2-pool-utils/contracts/lib/BasePoolMath.sol";
import "@balancer-labs/v2-solidity-utils/contracts/helpers/ScalingHelpers.sol";
import "../WeightedMath.sol";
library WeightedJoinsLib {
using WeightedPoolUserData for bytes;
function joinExactTokensInForBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory scalingFactors,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) internal pure returns (uint256, uint256[] memory) {
(uint256[] memory amountsIn, uint256 minBPTAmountOut) = userData.exactTokensInForBptOut();
InputHelpers.ensureInputLengthMatch(balances.length, amountsIn.length);
_upscaleArray(amountsIn, scalingFactors);
uint256 bptAmountOut = WeightedMath._calcBptOutGivenExactTokensIn(
balances,
normalizedWeights,
amountsIn,
totalSupply,
swapFeePercentage
);
_require(bptAmountOut >= minBPTAmountOut, Errors.BPT_OUT_MIN_AMOUNT);
return (bptAmountOut, amountsIn);
}
function joinTokenInForExactBPTOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256 totalSupply,
uint256 swapFeePercentage,
bytes memory userData
) internal pure returns (uint256, uint256[] memory) {
(uint256 bptAmountOut, uint256 tokenIndex) = userData.tokenInForExactBptOut();
// Note that there is no maximum amountIn parameter: this is handled by `IVault.joinPool`.
_require(tokenIndex < balances.length, Errors.OUT_OF_BOUNDS);
uint256 amountIn = WeightedMath._calcTokenInGivenExactBptOut(
balances[tokenIndex],
normalizedWeights[tokenIndex],
bptAmountOut,
totalSupply,
swapFeePercentage
);
// We join in a single token, so we initialize amountsIn with zeros
uint256[] memory amountsIn = new uint256[](balances.length);
// And then assign the result to the selected token
amountsIn[tokenIndex] = amountIn;
return (bptAmountOut, amountsIn);
}
function joinAllTokensInForExactBPTOut(
uint256[] memory balances,
uint256 totalSupply,
bytes memory userData
) internal pure returns (uint256 bptAmountOut, uint256[] memory amountsIn) {
bptAmountOut = userData.allTokensInForExactBptOut();
// Note that there is no maximum amountsIn parameter: this is handled by `IVault.joinPool`.
amountsIn = BasePoolMath.computeProportionalAmountsIn(balances, totalSupply, bptAmountOut);
}
}// 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/helpers/InputHelpers.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/Math.sol";
// These functions start with an underscore, as if they were part of a contract and not a library. At some point this
// should be fixed.
// solhint-disable private-vars-leading-underscore
library WeightedMath {
using FixedPoint for uint256;
// A minimum normalized weight imposes a maximum weight ratio. We need this due to limitations in the
// implementation of the power function, as these ratios are often exponents.
uint256 internal constant _MIN_WEIGHT = 0.01e18;
// Having a minimum normalized weight imposes a limit on the maximum number of tokens;
// i.e., the largest possible pool is one where all tokens have exactly the minimum weight.
uint256 internal constant _MAX_WEIGHTED_TOKENS = 100;
// Pool limits that arise from limitations in the fixed point power function (and the imposed 1:100 maximum weight
// ratio).
// Swap limits: amounts swapped may not be larger than this percentage of total balance.
uint256 internal constant _MAX_IN_RATIO = 0.3e18;
uint256 internal constant _MAX_OUT_RATIO = 0.3e18;
// Invariant growth limit: non-proportional joins cannot cause the invariant to increase by more than this ratio.
uint256 internal constant _MAX_INVARIANT_RATIO = 3e18;
// Invariant shrink limit: non-proportional exits cannot cause the invariant to decrease by less than this ratio.
uint256 internal constant _MIN_INVARIANT_RATIO = 0.7e18;
// About swap fees on joins and exits:
// Any join or exit that is not perfectly balanced (e.g. all single token joins or exits) is mathematically
// equivalent to a perfectly balanced join or exit followed by a series of swaps. Since these swaps would charge
// swap fees, it follows that (some) joins and exits should as well.
// On these operations, we split the token amounts in 'taxable' and 'non-taxable' portions, where the 'taxable' part
// is the one to which swap fees are applied.
// Invariant is used to collect protocol swap fees by comparing its value between two times.
// So we can round always to the same direction. It is also used to initiate the BPT amount
// and, because there is a minimum BPT, we round down the invariant.
function _calculateInvariant(uint256[] memory normalizedWeights, uint256[] memory balances)
internal
pure
returns (uint256 invariant)
{
/**********************************************************************************************
// invariant _____ //
// wi = weight index i | | wi //
// bi = balance index i | | bi ^ = i //
// i = invariant //
**********************************************************************************************/
invariant = FixedPoint.ONE;
for (uint256 i = 0; i < normalizedWeights.length; i++) {
invariant = invariant.mulDown(balances[i].powDown(normalizedWeights[i]));
}
_require(invariant > 0, Errors.ZERO_INVARIANT);
}
// Computes how many tokens can be taken out of a pool if `amountIn` are sent, given the
// current balances and weights.
function _calcOutGivenIn(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountIn
) internal pure returns (uint256) {
/**********************************************************************************************
// outGivenIn //
// aO = amountOut //
// bO = balanceOut //
// bI = balanceIn / / bI \ (wI / wO) \ //
// aI = amountIn aO = bO * | 1 - | -------------------------- | ^ | //
// wI = weightIn \ \ ( bI + aI ) / / //
// wO = weightOut //
**********************************************************************************************/
// Amount out, so we round down overall.
// The multiplication rounds down, and the subtrahend (power) rounds up (so the base rounds up too).
// Because bI / (bI + aI) <= 1, the exponent rounds down.
// Cannot exceed maximum in ratio
_require(amountIn <= balanceIn.mulDown(_MAX_IN_RATIO), Errors.MAX_IN_RATIO);
uint256 denominator = balanceIn.add(amountIn);
uint256 base = balanceIn.divUp(denominator);
uint256 exponent = weightIn.divDown(weightOut);
uint256 power = base.powUp(exponent);
return balanceOut.mulDown(power.complement());
}
// Computes how many tokens must be sent to a pool in order to take `amountOut`, given the
// current balances and weights.
function _calcInGivenOut(
uint256 balanceIn,
uint256 weightIn,
uint256 balanceOut,
uint256 weightOut,
uint256 amountOut
) internal pure returns (uint256) {
/**********************************************************************************************
// inGivenOut //
// aO = amountOut //
// bO = balanceOut //
// bI = balanceIn / / bO \ (wO / wI) \ //
// aI = amountIn aI = bI * | | -------------------------- | ^ - 1 | //
// wI = weightIn \ \ ( bO - aO ) / / //
// wO = weightOut //
**********************************************************************************************/
// Amount in, so we round up overall.
// The multiplication rounds up, and the power rounds up (so the base rounds up too).
// Because b0 / (b0 - a0) >= 1, the exponent rounds up.
// Cannot exceed maximum out ratio
_require(amountOut <= balanceOut.mulDown(_MAX_OUT_RATIO), Errors.MAX_OUT_RATIO);
uint256 base = balanceOut.divUp(balanceOut.sub(amountOut));
uint256 exponent = weightOut.divUp(weightIn);
uint256 power = base.powUp(exponent);
// Because the base is larger than one (and the power rounds up), the power should always be larger than one, so
// the following subtraction should never revert.
uint256 ratio = power.sub(FixedPoint.ONE);
return balanceIn.mulUp(ratio);
}
function _calcBptOutGivenExactTokensIn(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
// BPT out, so we round down overall.
uint256[] memory balanceRatiosWithFee = new uint256[](amountsIn.length);
uint256 invariantRatioWithFees = 0;
for (uint256 i = 0; i < balances.length; i++) {
balanceRatiosWithFee[i] = balances[i].add(amountsIn[i]).divDown(balances[i]);
invariantRatioWithFees = invariantRatioWithFees.add(balanceRatiosWithFee[i].mulDown(normalizedWeights[i]));
}
uint256 invariantRatio = _computeJoinExactTokensInInvariantRatio(
balances,
normalizedWeights,
amountsIn,
balanceRatiosWithFee,
invariantRatioWithFees,
swapFeePercentage
);
uint256 bptOut = (invariantRatio > FixedPoint.ONE)
? bptTotalSupply.mulDown(invariantRatio - FixedPoint.ONE)
: 0;
return bptOut;
}
function _calcBptOutGivenExactTokenIn(
uint256 balance,
uint256 normalizedWeight,
uint256 amountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
// BPT out, so we round down overall.
uint256 amountInWithoutFee;
{
uint256 balanceRatioWithFee = balance.add(amountIn).divDown(balance);
// The use of `normalizedWeight.complement()` assumes that the sum of all weights equals FixedPoint.ONE.
// This may not be the case when weights are stored in a denormalized format or during a gradual weight
// change due rounding errors during normalization or interpolation. This will result in a small difference
// between the output of this function and the equivalent `_calcBptOutGivenExactTokensIn` call.
uint256 invariantRatioWithFees = balanceRatioWithFee.mulDown(normalizedWeight).add(
normalizedWeight.complement()
);
if (balanceRatioWithFee > invariantRatioWithFees) {
uint256 nonTaxableAmount = invariantRatioWithFees > FixedPoint.ONE
? balance.mulDown(invariantRatioWithFees - FixedPoint.ONE)
: 0;
uint256 taxableAmount = amountIn.sub(nonTaxableAmount);
uint256 swapFee = taxableAmount.mulUp(swapFeePercentage);
amountInWithoutFee = nonTaxableAmount.add(taxableAmount.sub(swapFee));
} else {
amountInWithoutFee = amountIn;
// If a token's amount in is not being charged a swap fee then it might be zero.
// In this case, it's clear that the sender should receive no BPT.
if (amountInWithoutFee == 0) {
return 0;
}
}
}
uint256 balanceRatio = balance.add(amountInWithoutFee).divDown(balance);
uint256 invariantRatio = balanceRatio.powDown(normalizedWeight);
uint256 bptOut = (invariantRatio > FixedPoint.ONE)
? bptTotalSupply.mulDown(invariantRatio - FixedPoint.ONE)
: 0;
return bptOut;
}
/**
* @dev Intermediate function to avoid stack-too-deep errors.
*/
function _computeJoinExactTokensInInvariantRatio(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsIn,
uint256[] memory balanceRatiosWithFee,
uint256 invariantRatioWithFees,
uint256 swapFeePercentage
) private pure returns (uint256 invariantRatio) {
// Swap fees are charged on all tokens that are being added in a larger proportion than the overall invariant
// increase.
invariantRatio = FixedPoint.ONE;
for (uint256 i = 0; i < balances.length; i++) {
uint256 amountInWithoutFee;
if (balanceRatiosWithFee[i] > invariantRatioWithFees) {
// invariantRatioWithFees might be less than FixedPoint.ONE in edge scenarios due to rounding error,
// particularly if the weights don't exactly add up to 100%.
uint256 nonTaxableAmount = invariantRatioWithFees > FixedPoint.ONE
? balances[i].mulDown(invariantRatioWithFees - FixedPoint.ONE)
: 0;
uint256 swapFee = amountsIn[i].sub(nonTaxableAmount).mulUp(swapFeePercentage);
amountInWithoutFee = amountsIn[i].sub(swapFee);
} else {
amountInWithoutFee = amountsIn[i];
// If a token's amount in is not being charged a swap fee then it might be zero (e.g. when joining a
// Pool with only a subset of tokens). In this case, `balanceRatio` will equal `FixedPoint.ONE`, and
// the `invariantRatio` will not change at all. We therefore skip to the next iteration, avoiding
// the costly `powDown` call.
if (amountInWithoutFee == 0) {
continue;
}
}
uint256 balanceRatio = balances[i].add(amountInWithoutFee).divDown(balances[i]);
invariantRatio = invariantRatio.mulDown(balanceRatio.powDown(normalizedWeights[i]));
}
}
function _calcTokenInGivenExactBptOut(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
/******************************************************************************************
// tokenInForExactBPTOut //
// a = amountIn //
// b = balance / / totalBPT + bptOut \ (1 / w) \ //
// bptOut = bptAmountOut a = b * | | -------------------------- | ^ - 1 | //
// bpt = totalBPT \ \ totalBPT / / //
// w = weight //
******************************************************************************************/
// Token in, so we round up overall.
// Calculate the factor by which the invariant will increase after minting BPTAmountOut
uint256 invariantRatio = bptTotalSupply.add(bptAmountOut).divUp(bptTotalSupply);
_require(invariantRatio <= _MAX_INVARIANT_RATIO, Errors.MAX_OUT_BPT_FOR_TOKEN_IN);
// Calculate by how much the token balance has to increase to match the invariantRatio
uint256 balanceRatio = invariantRatio.powUp(FixedPoint.ONE.divUp(normalizedWeight));
uint256 amountInWithoutFee = balance.mulUp(balanceRatio.sub(FixedPoint.ONE));
// We can now compute how much extra balance is being deposited and used in virtual swaps, and charge swap fees
// accordingly.
uint256 taxableAmount = amountInWithoutFee.mulUp(normalizedWeight.complement());
uint256 nonTaxableAmount = amountInWithoutFee.sub(taxableAmount);
uint256 taxableAmountPlusFees = taxableAmount.divUp(swapFeePercentage.complement());
return nonTaxableAmount.add(taxableAmountPlusFees);
}
function _calcBptInGivenExactTokensOut(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
// BPT in, so we round up overall.
uint256[] memory balanceRatiosWithoutFee = new uint256[](amountsOut.length);
uint256 invariantRatioWithoutFees = 0;
for (uint256 i = 0; i < balances.length; i++) {
balanceRatiosWithoutFee[i] = balances[i].sub(amountsOut[i]).divUp(balances[i]);
invariantRatioWithoutFees = invariantRatioWithoutFees.add(
balanceRatiosWithoutFee[i].mulUp(normalizedWeights[i])
);
}
uint256 invariantRatio = _computeExitExactTokensOutInvariantRatio(
balances,
normalizedWeights,
amountsOut,
balanceRatiosWithoutFee,
invariantRatioWithoutFees,
swapFeePercentage
);
return bptTotalSupply.mulUp(invariantRatio.complement());
}
function _calcBptInGivenExactTokenOut(
uint256 balance,
uint256 normalizedWeight,
uint256 amountOut,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
// BPT in, so we round up overall.
uint256 balanceRatioWithoutFee = balance.sub(amountOut).divUp(balance);
uint256 invariantRatioWithoutFees = balanceRatioWithoutFee.mulUp(normalizedWeight).add(
normalizedWeight.complement()
);
uint256 amountOutWithFee;
if (invariantRatioWithoutFees > balanceRatioWithoutFee) {
// 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 nonTaxableAmount = balance.mulDown(invariantRatioWithoutFees.complement());
uint256 taxableAmount = amountOut.sub(nonTaxableAmount);
uint256 taxableAmountPlusFees = taxableAmount.divUp(swapFeePercentage.complement());
amountOutWithFee = nonTaxableAmount.add(taxableAmountPlusFees);
} else {
amountOutWithFee = amountOut;
// If a token's amount out is not being charged a swap fee then it might be zero.
// In this case, it's clear that the sender should not send any BPT.
if (amountOutWithFee == 0) {
return 0;
}
}
uint256 balanceRatio = balance.sub(amountOutWithFee).divDown(balance);
uint256 invariantRatio = balanceRatio.powDown(normalizedWeight);
return bptTotalSupply.mulUp(invariantRatio.complement());
}
/**
* @dev Intermediate function to avoid stack-too-deep errors.
*/
function _computeExitExactTokensOutInvariantRatio(
uint256[] memory balances,
uint256[] memory normalizedWeights,
uint256[] memory amountsOut,
uint256[] memory balanceRatiosWithoutFee,
uint256 invariantRatioWithoutFees,
uint256 swapFeePercentage
) private pure returns (uint256 invariantRatio) {
invariantRatio = FixedPoint.ONE;
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);
uint256 taxableAmountPlusFees = taxableAmount.divUp(swapFeePercentage.complement());
amountOutWithFee = nonTaxableAmount.add(taxableAmountPlusFees);
} else {
amountOutWithFee = amountsOut[i];
// If a token's amount out is not being charged a swap fee then it might be zero (e.g. when exiting a
// Pool with only a subset of tokens). In this case, `balanceRatio` will equal `FixedPoint.ONE`, and
// the `invariantRatio` will not change at all. We therefore skip to the next iteration, avoiding
// the costly `powDown` call.
if (amountOutWithFee == 0) {
continue;
}
}
uint256 balanceRatio = balances[i].sub(amountOutWithFee).divDown(balances[i]);
invariantRatio = invariantRatio.mulDown(balanceRatio.powDown(normalizedWeights[i]));
}
}
function _calcTokenOutGivenExactBptIn(
uint256 balance,
uint256 normalizedWeight,
uint256 bptAmountIn,
uint256 bptTotalSupply,
uint256 swapFeePercentage
) internal pure returns (uint256) {
/*****************************************************************************************
// exactBPTInForTokenOut //
// a = amountOut //
// b = balance / / totalBPT - bptIn \ (1 / w) \ //
// bptIn = bptAmountIn a = b * | 1 - | -------------------------- | ^ | //
// bpt = totalBPT \ \ totalBPT / / //
// w = weight //
*****************************************************************************************/
// Token out, so we round down overall. The multiplication rounds down, but the power rounds up (so the base
// rounds up). Because (totalBPT - bptIn) / totalBPT <= 1, the exponent rounds down.
// Calculate the factor by which the invariant will decrease after burning BPTAmountIn
uint256 invariantRatio = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply);
_require(invariantRatio >= _MIN_INVARIANT_RATIO, Errors.MIN_BPT_IN_FOR_TOKEN_OUT);
// Calculate by how much the token balance has to decrease to match invariantRatio
uint256 balanceRatio = invariantRatio.powUp(FixedPoint.ONE.divDown(normalizedWeight));
// Because of rounding up, balanceRatio can be greater than one. Using complement prevents reverts.
uint256 amountOutWithoutFee = balance.mulDown(balanceRatio.complement());
// We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result
// in swap fees.
// Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it
// to 'token out'. This results in slightly larger price impact. Fees are rounded up.
uint256 taxableAmount = amountOutWithoutFee.mulUp(normalizedWeight.complement());
uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount);
uint256 taxableAmountMinusFees = taxableAmount.mulUp(swapFeePercentage.complement());
return nonTaxableAmount.add(taxableAmountMinusFees);
}
/**
* @dev Calculate the amount of BPT which should be minted when adding a new token to the Pool.
*
* Note that normalizedWeight is set that it corresponds to the desired weight of this token *after* adding it.
* i.e. For a two token 50:50 pool which we want to turn into a 33:33:33 pool, we use a normalized weight of 33%
* @param totalSupply - the total supply of the Pool's BPT.
* @param normalizedWeight - the normalized weight of the token to be added (normalized relative to final weights)
*/
function _calcBptOutAddToken(uint256 totalSupply, uint256 normalizedWeight) internal pure returns (uint256) {
// The amount of BPT which is equivalent to the token being added may be calculated by the growth in the
// sum of the token weights, i.e. if we add a token which will make up 50% of the pool then we should receive
// 50% of the new supply of BPT.
//
// The growth in the total weight of the pool can be easily calculated by:
//
// weightSumRatio = totalWeight / (totalWeight - newTokenWeight)
//
// As we're working with normalized weights `totalWeight` is equal to 1.
uint256 weightSumRatio = FixedPoint.ONE.divDown(FixedPoint.ONE.sub(normalizedWeight));
// The amount of BPT to mint is then simply:
//
// toMint = totalSupply * (weightSumRatio - 1)
return totalSupply.mulDown(weightSumRatio.sub(FixedPoint.ONE));
}
}{
"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":"balances","type":"uint256[]"},{"internalType":"uint256","name":"bptAmountOut","type":"uint256"},{"internalType":"uint256","name":"totalBPT","type":"uint256"}],"name":"calcAllTokensInGivenExactBptOut","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"normalizedWeight","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcBptInGivenExactTokenOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcBptInGivenExactTokensOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"normalizedWeight","type":"uint256"}],"name":"calcBptOutAddToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"normalizedWeight","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcBptOutGivenExactTokenIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcBptOutGivenExactTokensIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balanceIn","type":"uint256"},{"internalType":"uint256","name":"weightIn","type":"uint256"},{"internalType":"uint256","name":"balanceOut","type":"uint256"},{"internalType":"uint256","name":"weightOut","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"calcInGivenOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balanceIn","type":"uint256"},{"internalType":"uint256","name":"weightIn","type":"uint256"},{"internalType":"uint256","name":"balanceOut","type":"uint256"},{"internalType":"uint256","name":"weightOut","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"calcOutGivenIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"normalizedWeight","type":"uint256"},{"internalType":"uint256","name":"bptAmountOut","type":"uint256"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcTokenInGivenExactBptOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"normalizedWeight","type":"uint256"},{"internalType":"uint256","name":"bptAmountIn","type":"uint256"},{"internalType":"uint256","name":"bptTotalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"calcTokenOutGivenExactBptIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"bptAmountIn","type":"uint256"},{"internalType":"uint256","name":"totalBPT","type":"uint256"}],"name":"calcTokensOutGivenExactBptIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"name":"calculateInvariant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256[]","name":"scalingFactors","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"exitBPTInForExactTokensOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"exitExactBPTInForTokenOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"exitExactBPTInForTokensOut","outputs":[{"internalType":"uint256","name":"bptAmountIn","type":"uint256"},{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"joinAllTokensInForExactBPTOut","outputs":[{"internalType":"uint256","name":"bptAmountOut","type":"uint256"},{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256[]","name":"scalingFactors","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"joinExactTokensInForBPTOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"joinTokenInForExactBPTOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b5061314c806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c8063588e1b44116100b2578063afc4d0db11610081578063d590510011610066578063d590510014611272578063ef2aca76146112a7578063f442dbc4146112dc57610136565b8063afc4d0db1461108d578063b540624d146110c257610136565b8063588e1b4414610c895780637351a78614610e395780637f1ae8a914610f3157806390043a5814610f6657610136565b8063120c0c63116101095780632ac71a3e116100ee5780632ac71a3e1461086e5780633d0b05e914610aac5780634c888cbb14610c6657610136565b8063120c0c63146104fe5780631b2db0ea1461073c57610136565b806303a5b64b1461013b578063098e0189146102c85780630c78bb4e146104825780630ccd8941146104c9575b600080fd5b61026d6004803603606081101561015157600080fd5b81019060208101813564010000000081111561016c57600080fd5b82018360208201111561017e57600080fd5b803590602001918460208302840111640100000000831117156101a057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359590949093506040810192506020013590506401000000008111156101f857600080fd5b82018360208201111561020a57600080fd5b8035906020019184600183028401116401000000008311171561022c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611384945050505050565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156102b357818101518382015260200161029b565b50505050905001935050505060405180910390f35b61026d600480360360a08110156102de57600080fd5b8101906020810181356401000000008111156102f957600080fd5b82018360208201111561030b57600080fd5b8035906020019184602083028401116401000000008311171561032d57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460208302840111640100000000831117156103b157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359560208601359591945092506060810191506040013564010000000081111561040d57600080fd5b82018360208201111561041f57600080fd5b8035906020019184600183028401116401000000008311171561044157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061139f945050505050565b6104b7600480360360a081101561049857600080fd5b50803590602081013590604081013590606081013590608001356113be565b60408051918252519081900360200190f35b6104b7600480360360a08110156104df57600080fd5b50803590602081013590604081013590606081013590608001356113d9565b61026d600480360360c081101561051457600080fd5b81019060208101813564010000000081111561052f57600080fd5b82018360208201111561054157600080fd5b8035906020019184602083028401116401000000008311171561056357600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156105b357600080fd5b8201836020820111156105c557600080fd5b803590602001918460208302840111640100000000831117156105e757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561063757600080fd5b82018360208201111561064957600080fd5b8035906020019184602083028401116401000000008311171561066b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435956020860135959194509250606081019150604001356401000000008111156106c757600080fd5b8201836020820111156106d957600080fd5b803590602001918460018302840111640100000000831117156106fb57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506113e8945050505050565b61026d6004803603606081101561075257600080fd5b81019060208101813564010000000081111561076d57600080fd5b82018360208201111561077f57600080fd5b803590602001918460208302840111640100000000831117156107a157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359590949093506040810192506020013590506401000000008111156107f957600080fd5b82018360208201111561080b57600080fd5b8035906020019184600183028401116401000000008311171561082d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611409945050505050565b61026d600480360360c081101561088457600080fd5b81019060208101813564010000000081111561089f57600080fd5b8201836020820111156108b157600080fd5b803590602001918460208302840111640100000000831117156108d357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561092357600080fd5b82018360208201111561093557600080fd5b8035906020019184602083028401116401000000008311171561095757600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156109a757600080fd5b8201836020820111156109b957600080fd5b803590602001918460208302840111640100000000831117156109db57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135640100000000811115610a3757600080fd5b820183602082011115610a4957600080fd5b80359060200191846001830284011164010000000083111715610a6b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611418945050505050565b61026d600480360360a0811015610ac257600080fd5b810190602081018135640100000000811115610add57600080fd5b820183602082011115610aef57600080fd5b80359060200191846020830284011164010000000083111715610b1157600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610b6157600080fd5b820183602082011115610b7357600080fd5b80359060200191846020830284011164010000000083111715610b9557600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135640100000000811115610bf157600080fd5b820183602082011115610c0357600080fd5b80359060200191846001830284011164010000000083111715610c2557600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061142a945050505050565b6104b760048036036040811015610c7c57600080fd5b508035906020013561143b565b6104b7600480360360a0811015610c9f57600080fd5b810190602081018135640100000000811115610cba57600080fd5b820183602082011115610ccc57600080fd5b80359060200191846020830284011164010000000083111715610cee57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610d3e57600080fd5b820183602082011115610d5057600080fd5b80359060200191846020830284011164010000000083111715610d7257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610dc257600080fd5b820183602082011115610dd457600080fd5b80359060200191846020830284011164010000000083111715610df657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505082359350505060200135611450565b610ee160048036036060811015610e4f57600080fd5b810190602081018135640100000000811115610e6a57600080fd5b820183602082011115610e7c57600080fd5b80359060200191846020830284011164010000000083111715610e9e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550508235935050506020013561145f565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610f1d578181015183820152602001610f05565b505050509050019250505060405180910390f35b6104b7600480360360a0811015610f4757600080fd5b5080359060208101359060408101359060608101359060800135611474565b6104b760048036036040811015610f7c57600080fd5b810190602081018135640100000000811115610f9757600080fd5b820183602082011115610fa957600080fd5b80359060200191846020830284011164010000000083111715610fcb57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561101b57600080fd5b82018360208201111561102d57600080fd5b8035906020019184602083028401116401000000008311171561104f57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611483945050505050565b6104b7600480360360a08110156110a357600080fd5b508035906020810135906040810135906060810135906080013561148f565b6104b7600480360360a08110156110d857600080fd5b8101906020810181356401000000008111156110f357600080fd5b82018360208201111561110557600080fd5b8035906020019184602083028401116401000000008311171561112757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561117757600080fd5b82018360208201111561118957600080fd5b803590602001918460208302840111640100000000831117156111ab57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156111fb57600080fd5b82018360208201111561120d57600080fd5b8035906020019184602083028401116401000000008311171561122f57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550508235935050506020013561149e565b6104b7600480360360a081101561128857600080fd5b50803590602081013590604081013590606081013590608001356114ad565b6104b7600480360360a08110156112bd57600080fd5b50803590602081013590604081013590606081013590608001356114bc565b610ee1600480360360608110156112f257600080fd5b81019060208101813564010000000081111561130d57600080fd5b82018360208201111561131f57600080fd5b8035906020019184602083028401116401000000008311171561134157600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955050823593505050602001356114cb565b600060606113938585856114d8565b91509150935093915050565b600060606113b087878787876114fc565b915091509550959350505050565b60006113cd86868686866115c5565b90505b95945050505050565b60006113cd8686868686611640565b600060606113fa8888888888886116fd565b91509150965096945050505050565b60006060611393858585611756565b600060606113fa888888888888611770565b600060606113b087878787876117b9565b60006114478383611810565b90505b92915050565b60006113cd8686868686611855565b606061146c848385611993565b949350505050565b60006113cd8686868686611a2c565b60006114478383611ac2565b60006113cd8686868686611b34565b60006113cd8686868686611c71565b60006113cd8686868686611d86565b60006113cd8686868686611dfc565b606061146c848385611ed8565b600060606114e583611f68565b91506114f2858584611993565b9050935093915050565b6000606060008061150c85611f8a565b9150915061151e895182106064611fb8565b60006115538a838151811061152f57fe5b60200260200101518a848151811061154357fe5b6020026020010151858b8b611a2c565b905060608a5167ffffffffffffffff8111801561156f57600080fd5b50604051908082528060200260200182016040528015611599578160200160208202803683370190505b509050818184815181106115a957fe5b6020908102919091010152929a92995091975050505050505050565b60006115e76115dc87670429d069189e0000611fca565b831115610130611fb8565b60006115f38784612002565b905060006116018883612014565b9050600061160f888761206b565b9050600061161d83836120ab565b905061163261162b82612150565b8990611fca565b9a9950505050505050505050565b600080611657846116518188612162565b90612014565b90506116706709b6e64a8ec60000821015610132611fb8565b600061168e611687670de0b6b3a76400008961206b565b83906120ab565b905060006116a561169e83612150565b8a90611fca565b905060006116bc6116b58a612150565b8390612178565b905060006116ca8383612162565b905060006116e16116da89612150565b8490612178565b90506116ed8282612002565b9c9b505050505050505050505050565b6000606080600061170d856121b0565b9150915061171d8a51835161226d565b611727828961227a565b60006117368b8b858b8b611c71565b90506117468282101560d0611fb8565b9a91995090975050505050505050565b6000606061176383611f68565b91506114f2858584611ed8565b60006060806000611780856121b0565b9150915061179082518b5161226d565b61179a828961227a565b60006117a98b8b858b8b611855565b90506117468282111560cf611fb8565b600060606000806117c985611f8a565b915091506117db895182106064611fb8565b60006115538a83815181106117ec57fe5b60200260200101518a848151811061180057fe5b6020026020010151858b8b611640565b600080611837611828670de0b6b3a764000085612162565b670de0b6b3a76400009061206b565b905061146c61184e82670de0b6b3a7640000612162565b8590611fca565b60006060845167ffffffffffffffff8111801561187157600080fd5b5060405190808252806020026020018201604052801561189b578160200160208202803683370190505b5090506000805b8851811015611960576118fb8982815181106118ba57fe5b60200260200101516116518984815181106118d157fe5b60200260200101518c85815181106118e557fe5b602002602001015161216290919063ffffffff16565b83828151811061190757fe5b60200260200101818152505061195661194f89838151811061192557fe5b602002602001015185848151811061193957fe5b602002602001015161217890919063ffffffff16565b8390612002565b91506001016118a2565b50600061197189898986868a6122e9565b905061198661197f82612150565b8790612178565b9998505050505050505050565b606060006119a18385612014565b9050845167ffffffffffffffff811180156119bb57600080fd5b506040519080825280602002602001820160405280156119e5578160200160208202803683370190505b50915060005b8551811015611a2357611a048287838151811061193957fe5b838281518110611a1057fe5b60209081029190910101526001016119eb565b50509392505050565b600080611a3d846116518188612002565b9050611a566729a2241af62c0000821115610133611fb8565b6000611a6d611687670de0b6b3a764000089612014565b90506000611a8d611a8683670de0b6b3a7640000612162565b8a90612178565b90506000611a9d6116b58a612150565b90506000611aab8383612162565b905060006116e1611abb89612150565b8490612014565b670de0b6b3a764000060005b8351811015611b2457611b1a611b13858381518110611ae957fe5b6020026020010151858481518110611afd57fe5b602002602001015161240090919063ffffffff16565b8390611fca565b9150600101611ace565b5061144a60008211610137611fb8565b60008080611b4c88611b468189612002565b9061206b565b90506000611b6c611b5c89612150565b611b66848b611fca565b90612002565b905080821115611bf6576000670de0b6b3a76400008211611b8e576000611bba565b611bba8a7ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401611fca565b90506000611bc88983612162565b90506000611bd68289612178565b9050611bec611be58383612162565b8490612002565b9550505050611c0a565b86925082611c0a57600093505050506113d0565b5060009050611c1d88611b468185612002565b90506000611c2b8289612400565b90506000670de0b6b3a76400008211611c45576000611632565b611632877ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401611fca565b60006060845167ffffffffffffffff81118015611c8d57600080fd5b50604051908082528060200260200182016040528015611cb7578160200160208202803683370190505b5090506000805b8851811015611d7557611d17898281518110611cd657fe5b6020026020010151611b46898481518110611ced57fe5b60200260200101518c8581518110611d0157fe5b602002602001015161200290919063ffffffff16565b838281518110611d2357fe5b602002602001018181525050611d6b61194f898381518110611d4157fe5b6020026020010151858481518110611d5557fe5b6020026020010151611fca90919063ffffffff16565b9150600101611cbe565b506000611c2b89898986868a612499565b6000611da8611d9d85670429d069189e0000611fca565b831115610131611fb8565b6000611dbe611db78685612162565b8690612014565b90506000611dcc8588612014565b90506000611dda83836120ab565b90506000611df082670de0b6b3a7640000612162565b90506116328a82612178565b600080611e0d876116518188612162565b90506000611e27611e1d88612150565b611b66848a612178565b9050600082821115611e83576000611e48611e4184612150565b8b90611fca565b90506000611e568983612162565b90506000611e6d611e6689612150565b8390612014565b9050611e798382612002565b9350505050611e96565b508580611e9657600093505050506113d0565b6000611ea68a611b468185612162565b90506000611eb4828b612400565b9050611ec9611ec282612150565b8990612178565b9b9a5050505050505050505050565b60606000611ee6838561206b565b9050845167ffffffffffffffff81118015611f0057600080fd5b50604051908082528060200260200182016040528015611f2a578160200160208202803683370190505b50915060005b8551811015611a2357611f4982878381518110611d5557fe5b838281518110611f5557fe5b6020908102919091010152600101611f30565b6000818060200190516040811015611f7f57600080fd5b506020015192915050565b600080828060200190516060811015611fa257600080fd5b5060208101516040909101519094909350915050565b81611fc657611fc6816125a5565b5050565b6000828202611fee841580611fe7575083858381611fe457fe5b04145b6003611fb8565b670de0b6b3a7640000815b04949350505050565b60008282016114478482101583611fb8565b60006120238215156004611fb8565b670de0b6b3a7640000830261205584158061204e5750670de0b6b3a764000085838161204b57fe5b04145b6005611fb8565b6001836001830304018115150291505092915050565b600061207a8215156004611fb8565b670de0b6b3a764000083026120a284158061204e5750670de0b6b3a764000085838161204b57fe5b828181611ff957fe5b6000670de0b6b3a76400008214156120c457508161144a565b671bc16d674ec800008214156120e5576120de8384612178565b905061144a565b673782dace9d9000008214156121155760006121018485612178565b905061210d8182612178565b91505061144a565b600061212184846125d2565b9050600061213b61213483612710612178565b6001612002565b90506121478282612002565b9250505061144a565b670de0b6b3a764000081810391100290565b6000612172838311156001611fb8565b50900390565b6000828202612192841580611fe7575083858381611fe457fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b606060008280602001905160608110156121c957600080fd5b8151602083018051604051929492938301929190846401000000008211156121f057600080fd5b90830190602082018581111561220557600080fd5b825186602082028301116401000000008211171561222257600080fd5b82525081516020918201928201910280838360005b8381101561224f578181015183820152602001612237565b50505050919091016040525060200151929792965091945050505050565b611fc68183146067611fb8565b8151815161228990829061226d565b60005b818110156122e3576122c48482815181106122a357fe5b60200260200101518483815181106122b757fe5b6020026020010151611fca565b8482815181106122d057fe5b602090810291909101015260010161228c565b50505050565b670de0b6b3a764000060005b87518110156123f557600085828151811061230c57fe5b602002602001015185111561236f57600061233561232987612150565b8b8581518110611d5557fe5b90506000612349828a86815181106118e557fe5b90506000612359611e6688612150565b90506123658382612002565b9350505050612394565b86828151811061237b57fe5b60200260200101519050806000141561239457506123ed565b60006123bd8a84815181106123a557fe5b6020026020010151611b46848d87815181106118e557fe5b90506123e861184e8a85815181106123d157fe5b60200260200101518361240090919063ffffffff16565b935050505b6001016122f5565b509695505050505050565b6000670de0b6b3a764000082141561241957508161144a565b671bc16d674ec80000821415612433576120de8384611fca565b673782dace9d90000082141561245b57600061244f8485611fca565b905061210d8182611fca565b600061246784846125d2565b9050600061247a61213483612710612178565b90508082101561248f5760009250505061144a565b6121478282612162565b670de0b6b3a764000060005b87518110156123f5576000848683815181106124bd57fe5b60200260200101511115612536576000670de0b6b3a764000086116124e35760006124fd565b6124fd670de0b6b3a764000087038b8581518110611d5557fe5b9050600061251b86612515848c88815181106118e557fe5b90612178565b905061252d818a86815181106118e557fe5b9250505061255b565b86828151811061254257fe5b60200260200101519050806000141561255b575061259d565b60006125848a848151811061256c57fe5b6020026020010151611b46848d8781518110611d0157fe5b905061259861184e8a85815181106123d157fe5b935050505b6001016124a5565b6125cf817f42414c00000000000000000000000000000000000000000000000000000000006126f2565b50565b6000816125e85750670de0b6b3a764000061144a565b826125f55750600061144a565b61260560ff84901c156006611fb8565b8261262b770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007611fb8565b826000670c7d713b49da00008313801561264c5750670f43fc2c04ee000083125b1561268357600061265c8461276d565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612691565b8161268d846128a6565b0290505b670de0b6b3a764000090056126df7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc000082128015906126d8575068070c1cc73b00c800008213155b6008611fb8565b6126e881612c46565b9695505050505050565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fd5b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401907fffffffffffffffffffffffffffffffffff3f68318436f8ea4cb460f000000000850102816127b957fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f820581019050806002029450505050505b919050565b6000670de0b6b3a76400008212156128e3576128d9826ec097ce7bc90715b34b9f1000000000816128d357fe5b056128a6565b60000390506128a1565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261293457770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261296c576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126129b4576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126129ef576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf8508312612a2657693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e28312612a5d57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d038312612a925768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb417461211108312612abd57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d8312612af2576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312612b27576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312612b5b576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312612b8f576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d631000008086030281612bb257fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000612c8b7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc00008312158015612c84575068070c1cc73b00c800008313155b6009611fb8565b6000821215612cbf57612ca082600003612c46565b6ec097ce7bc90715b34b9f100000000081612cb757fe5b0590506128a1565b60006806f05b59d3b20000008312612d1557507ffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4e00000090910190770195e54c5dd42177f53a27172fa9ec630262827000000000612d61565b6803782dace9d90000008312612d5d57507ffffffffffffffffffffffffffffffffffffffffffffffffc87d2531627000000909101906b1425982cf597cd205cef7380612d61565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412612dc7577fffffffffffffffffffffffffffffffffffffffffffffff5287143a539e0000009093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412612e19577fffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf0000009093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412612e69577fffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e78000009093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412612eb9577fffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c000009093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412612f08577ffffffffffffffffffffffffffffffffffffffffffffffff5287143a539e000009093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412612f57577ffffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf000009093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412612fa6577ffffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e7800009093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412612ff5577ffffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c00009093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d6310000084840205850205969550505050505056fea264697066735822122092f5a8f0d4c4f6dd2b5bcc4417c23e8281ce30d7b8be1b4a8648ae94e29bae8164736f6c63430007010033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101365760003560e01c8063588e1b44116100b2578063afc4d0db11610081578063d590510011610066578063d590510014611272578063ef2aca76146112a7578063f442dbc4146112dc57610136565b8063afc4d0db1461108d578063b540624d146110c257610136565b8063588e1b4414610c895780637351a78614610e395780637f1ae8a914610f3157806390043a5814610f6657610136565b8063120c0c63116101095780632ac71a3e116100ee5780632ac71a3e1461086e5780633d0b05e914610aac5780634c888cbb14610c6657610136565b8063120c0c63146104fe5780631b2db0ea1461073c57610136565b806303a5b64b1461013b578063098e0189146102c85780630c78bb4e146104825780630ccd8941146104c9575b600080fd5b61026d6004803603606081101561015157600080fd5b81019060208101813564010000000081111561016c57600080fd5b82018360208201111561017e57600080fd5b803590602001918460208302840111640100000000831117156101a057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359590949093506040810192506020013590506401000000008111156101f857600080fd5b82018360208201111561020a57600080fd5b8035906020019184600183028401116401000000008311171561022c57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611384945050505050565b6040518083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156102b357818101518382015260200161029b565b50505050905001935050505060405180910390f35b61026d600480360360a08110156102de57600080fd5b8101906020810181356401000000008111156102f957600080fd5b82018360208201111561030b57600080fd5b8035906020019184602083028401116401000000008311171561032d57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561037d57600080fd5b82018360208201111561038f57600080fd5b803590602001918460208302840111640100000000831117156103b157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359560208601359591945092506060810191506040013564010000000081111561040d57600080fd5b82018360208201111561041f57600080fd5b8035906020019184600183028401116401000000008311171561044157600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061139f945050505050565b6104b7600480360360a081101561049857600080fd5b50803590602081013590604081013590606081013590608001356113be565b60408051918252519081900360200190f35b6104b7600480360360a08110156104df57600080fd5b50803590602081013590604081013590606081013590608001356113d9565b61026d600480360360c081101561051457600080fd5b81019060208101813564010000000081111561052f57600080fd5b82018360208201111561054157600080fd5b8035906020019184602083028401116401000000008311171561056357600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156105b357600080fd5b8201836020820111156105c557600080fd5b803590602001918460208302840111640100000000831117156105e757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561063757600080fd5b82018360208201111561064957600080fd5b8035906020019184602083028401116401000000008311171561066b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092958435956020860135959194509250606081019150604001356401000000008111156106c757600080fd5b8201836020820111156106d957600080fd5b803590602001918460018302840111640100000000831117156106fb57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506113e8945050505050565b61026d6004803603606081101561075257600080fd5b81019060208101813564010000000081111561076d57600080fd5b82018360208201111561077f57600080fd5b803590602001918460208302840111640100000000831117156107a157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359590949093506040810192506020013590506401000000008111156107f957600080fd5b82018360208201111561080b57600080fd5b8035906020019184600183028401116401000000008311171561082d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611409945050505050565b61026d600480360360c081101561088457600080fd5b81019060208101813564010000000081111561089f57600080fd5b8201836020820111156108b157600080fd5b803590602001918460208302840111640100000000831117156108d357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561092357600080fd5b82018360208201111561093557600080fd5b8035906020019184602083028401116401000000008311171561095757600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156109a757600080fd5b8201836020820111156109b957600080fd5b803590602001918460208302840111640100000000831117156109db57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135640100000000811115610a3757600080fd5b820183602082011115610a4957600080fd5b80359060200191846001830284011164010000000083111715610a6b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611418945050505050565b61026d600480360360a0811015610ac257600080fd5b810190602081018135640100000000811115610add57600080fd5b820183602082011115610aef57600080fd5b80359060200191846020830284011164010000000083111715610b1157600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610b6157600080fd5b820183602082011115610b7357600080fd5b80359060200191846020830284011164010000000083111715610b9557600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295843595602086013595919450925060608101915060400135640100000000811115610bf157600080fd5b820183602082011115610c0357600080fd5b80359060200191846001830284011164010000000083111715610c2557600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061142a945050505050565b6104b760048036036040811015610c7c57600080fd5b508035906020013561143b565b6104b7600480360360a0811015610c9f57600080fd5b810190602081018135640100000000811115610cba57600080fd5b820183602082011115610ccc57600080fd5b80359060200191846020830284011164010000000083111715610cee57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610d3e57600080fd5b820183602082011115610d5057600080fd5b80359060200191846020830284011164010000000083111715610d7257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610dc257600080fd5b820183602082011115610dd457600080fd5b80359060200191846020830284011164010000000083111715610df657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505082359350505060200135611450565b610ee160048036036060811015610e4f57600080fd5b810190602081018135640100000000811115610e6a57600080fd5b820183602082011115610e7c57600080fd5b80359060200191846020830284011164010000000083111715610e9e57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550508235935050506020013561145f565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610f1d578181015183820152602001610f05565b505050509050019250505060405180910390f35b6104b7600480360360a0811015610f4757600080fd5b5080359060208101359060408101359060608101359060800135611474565b6104b760048036036040811015610f7c57600080fd5b810190602081018135640100000000811115610f9757600080fd5b820183602082011115610fa957600080fd5b80359060200191846020830284011164010000000083111715610fcb57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561101b57600080fd5b82018360208201111561102d57600080fd5b8035906020019184602083028401116401000000008311171561104f57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611483945050505050565b6104b7600480360360a08110156110a357600080fd5b508035906020810135906040810135906060810135906080013561148f565b6104b7600480360360a08110156110d857600080fd5b8101906020810181356401000000008111156110f357600080fd5b82018360208201111561110557600080fd5b8035906020019184602083028401116401000000008311171561112757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561117757600080fd5b82018360208201111561118957600080fd5b803590602001918460208302840111640100000000831117156111ab57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156111fb57600080fd5b82018360208201111561120d57600080fd5b8035906020019184602083028401116401000000008311171561122f57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550508235935050506020013561149e565b6104b7600480360360a081101561128857600080fd5b50803590602081013590604081013590606081013590608001356114ad565b6104b7600480360360a08110156112bd57600080fd5b50803590602081013590604081013590606081013590608001356114bc565b610ee1600480360360608110156112f257600080fd5b81019060208101813564010000000081111561130d57600080fd5b82018360208201111561131f57600080fd5b8035906020019184602083028401116401000000008311171561134157600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955050823593505050602001356114cb565b600060606113938585856114d8565b91509150935093915050565b600060606113b087878787876114fc565b915091509550959350505050565b60006113cd86868686866115c5565b90505b95945050505050565b60006113cd8686868686611640565b600060606113fa8888888888886116fd565b91509150965096945050505050565b60006060611393858585611756565b600060606113fa888888888888611770565b600060606113b087878787876117b9565b60006114478383611810565b90505b92915050565b60006113cd8686868686611855565b606061146c848385611993565b949350505050565b60006113cd8686868686611a2c565b60006114478383611ac2565b60006113cd8686868686611b34565b60006113cd8686868686611c71565b60006113cd8686868686611d86565b60006113cd8686868686611dfc565b606061146c848385611ed8565b600060606114e583611f68565b91506114f2858584611993565b9050935093915050565b6000606060008061150c85611f8a565b9150915061151e895182106064611fb8565b60006115538a838151811061152f57fe5b60200260200101518a848151811061154357fe5b6020026020010151858b8b611a2c565b905060608a5167ffffffffffffffff8111801561156f57600080fd5b50604051908082528060200260200182016040528015611599578160200160208202803683370190505b509050818184815181106115a957fe5b6020908102919091010152929a92995091975050505050505050565b60006115e76115dc87670429d069189e0000611fca565b831115610130611fb8565b60006115f38784612002565b905060006116018883612014565b9050600061160f888761206b565b9050600061161d83836120ab565b905061163261162b82612150565b8990611fca565b9a9950505050505050505050565b600080611657846116518188612162565b90612014565b90506116706709b6e64a8ec60000821015610132611fb8565b600061168e611687670de0b6b3a76400008961206b565b83906120ab565b905060006116a561169e83612150565b8a90611fca565b905060006116bc6116b58a612150565b8390612178565b905060006116ca8383612162565b905060006116e16116da89612150565b8490612178565b90506116ed8282612002565b9c9b505050505050505050505050565b6000606080600061170d856121b0565b9150915061171d8a51835161226d565b611727828961227a565b60006117368b8b858b8b611c71565b90506117468282101560d0611fb8565b9a91995090975050505050505050565b6000606061176383611f68565b91506114f2858584611ed8565b60006060806000611780856121b0565b9150915061179082518b5161226d565b61179a828961227a565b60006117a98b8b858b8b611855565b90506117468282111560cf611fb8565b600060606000806117c985611f8a565b915091506117db895182106064611fb8565b60006115538a83815181106117ec57fe5b60200260200101518a848151811061180057fe5b6020026020010151858b8b611640565b600080611837611828670de0b6b3a764000085612162565b670de0b6b3a76400009061206b565b905061146c61184e82670de0b6b3a7640000612162565b8590611fca565b60006060845167ffffffffffffffff8111801561187157600080fd5b5060405190808252806020026020018201604052801561189b578160200160208202803683370190505b5090506000805b8851811015611960576118fb8982815181106118ba57fe5b60200260200101516116518984815181106118d157fe5b60200260200101518c85815181106118e557fe5b602002602001015161216290919063ffffffff16565b83828151811061190757fe5b60200260200101818152505061195661194f89838151811061192557fe5b602002602001015185848151811061193957fe5b602002602001015161217890919063ffffffff16565b8390612002565b91506001016118a2565b50600061197189898986868a6122e9565b905061198661197f82612150565b8790612178565b9998505050505050505050565b606060006119a18385612014565b9050845167ffffffffffffffff811180156119bb57600080fd5b506040519080825280602002602001820160405280156119e5578160200160208202803683370190505b50915060005b8551811015611a2357611a048287838151811061193957fe5b838281518110611a1057fe5b60209081029190910101526001016119eb565b50509392505050565b600080611a3d846116518188612002565b9050611a566729a2241af62c0000821115610133611fb8565b6000611a6d611687670de0b6b3a764000089612014565b90506000611a8d611a8683670de0b6b3a7640000612162565b8a90612178565b90506000611a9d6116b58a612150565b90506000611aab8383612162565b905060006116e1611abb89612150565b8490612014565b670de0b6b3a764000060005b8351811015611b2457611b1a611b13858381518110611ae957fe5b6020026020010151858481518110611afd57fe5b602002602001015161240090919063ffffffff16565b8390611fca565b9150600101611ace565b5061144a60008211610137611fb8565b60008080611b4c88611b468189612002565b9061206b565b90506000611b6c611b5c89612150565b611b66848b611fca565b90612002565b905080821115611bf6576000670de0b6b3a76400008211611b8e576000611bba565b611bba8a7ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401611fca565b90506000611bc88983612162565b90506000611bd68289612178565b9050611bec611be58383612162565b8490612002565b9550505050611c0a565b86925082611c0a57600093505050506113d0565b5060009050611c1d88611b468185612002565b90506000611c2b8289612400565b90506000670de0b6b3a76400008211611c45576000611632565b611632877ffffffffffffffffffffffffffffffffffffffffffffffffff21f494c589c00008401611fca565b60006060845167ffffffffffffffff81118015611c8d57600080fd5b50604051908082528060200260200182016040528015611cb7578160200160208202803683370190505b5090506000805b8851811015611d7557611d17898281518110611cd657fe5b6020026020010151611b46898481518110611ced57fe5b60200260200101518c8581518110611d0157fe5b602002602001015161200290919063ffffffff16565b838281518110611d2357fe5b602002602001018181525050611d6b61194f898381518110611d4157fe5b6020026020010151858481518110611d5557fe5b6020026020010151611fca90919063ffffffff16565b9150600101611cbe565b506000611c2b89898986868a612499565b6000611da8611d9d85670429d069189e0000611fca565b831115610131611fb8565b6000611dbe611db78685612162565b8690612014565b90506000611dcc8588612014565b90506000611dda83836120ab565b90506000611df082670de0b6b3a7640000612162565b90506116328a82612178565b600080611e0d876116518188612162565b90506000611e27611e1d88612150565b611b66848a612178565b9050600082821115611e83576000611e48611e4184612150565b8b90611fca565b90506000611e568983612162565b90506000611e6d611e6689612150565b8390612014565b9050611e798382612002565b9350505050611e96565b508580611e9657600093505050506113d0565b6000611ea68a611b468185612162565b90506000611eb4828b612400565b9050611ec9611ec282612150565b8990612178565b9b9a5050505050505050505050565b60606000611ee6838561206b565b9050845167ffffffffffffffff81118015611f0057600080fd5b50604051908082528060200260200182016040528015611f2a578160200160208202803683370190505b50915060005b8551811015611a2357611f4982878381518110611d5557fe5b838281518110611f5557fe5b6020908102919091010152600101611f30565b6000818060200190516040811015611f7f57600080fd5b506020015192915050565b600080828060200190516060811015611fa257600080fd5b5060208101516040909101519094909350915050565b81611fc657611fc6816125a5565b5050565b6000828202611fee841580611fe7575083858381611fe457fe5b04145b6003611fb8565b670de0b6b3a7640000815b04949350505050565b60008282016114478482101583611fb8565b60006120238215156004611fb8565b670de0b6b3a7640000830261205584158061204e5750670de0b6b3a764000085838161204b57fe5b04145b6005611fb8565b6001836001830304018115150291505092915050565b600061207a8215156004611fb8565b670de0b6b3a764000083026120a284158061204e5750670de0b6b3a764000085838161204b57fe5b828181611ff957fe5b6000670de0b6b3a76400008214156120c457508161144a565b671bc16d674ec800008214156120e5576120de8384612178565b905061144a565b673782dace9d9000008214156121155760006121018485612178565b905061210d8182612178565b91505061144a565b600061212184846125d2565b9050600061213b61213483612710612178565b6001612002565b90506121478282612002565b9250505061144a565b670de0b6b3a764000081810391100290565b6000612172838311156001611fb8565b50900390565b6000828202612192841580611fe7575083858381611fe457fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b606060008280602001905160608110156121c957600080fd5b8151602083018051604051929492938301929190846401000000008211156121f057600080fd5b90830190602082018581111561220557600080fd5b825186602082028301116401000000008211171561222257600080fd5b82525081516020918201928201910280838360005b8381101561224f578181015183820152602001612237565b50505050919091016040525060200151929792965091945050505050565b611fc68183146067611fb8565b8151815161228990829061226d565b60005b818110156122e3576122c48482815181106122a357fe5b60200260200101518483815181106122b757fe5b6020026020010151611fca565b8482815181106122d057fe5b602090810291909101015260010161228c565b50505050565b670de0b6b3a764000060005b87518110156123f557600085828151811061230c57fe5b602002602001015185111561236f57600061233561232987612150565b8b8581518110611d5557fe5b90506000612349828a86815181106118e557fe5b90506000612359611e6688612150565b90506123658382612002565b9350505050612394565b86828151811061237b57fe5b60200260200101519050806000141561239457506123ed565b60006123bd8a84815181106123a557fe5b6020026020010151611b46848d87815181106118e557fe5b90506123e861184e8a85815181106123d157fe5b60200260200101518361240090919063ffffffff16565b935050505b6001016122f5565b509695505050505050565b6000670de0b6b3a764000082141561241957508161144a565b671bc16d674ec80000821415612433576120de8384611fca565b673782dace9d90000082141561245b57600061244f8485611fca565b905061210d8182611fca565b600061246784846125d2565b9050600061247a61213483612710612178565b90508082101561248f5760009250505061144a565b6121478282612162565b670de0b6b3a764000060005b87518110156123f5576000848683815181106124bd57fe5b60200260200101511115612536576000670de0b6b3a764000086116124e35760006124fd565b6124fd670de0b6b3a764000087038b8581518110611d5557fe5b9050600061251b86612515848c88815181106118e557fe5b90612178565b905061252d818a86815181106118e557fe5b9250505061255b565b86828151811061254257fe5b60200260200101519050806000141561255b575061259d565b60006125848a848151811061256c57fe5b6020026020010151611b46848d8781518110611d0157fe5b905061259861184e8a85815181106123d157fe5b935050505b6001016124a5565b6125cf817f42414c00000000000000000000000000000000000000000000000000000000006126f2565b50565b6000816125e85750670de0b6b3a764000061144a565b826125f55750600061144a565b61260560ff84901c156006611fb8565b8261262b770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007611fb8565b826000670c7d713b49da00008313801561264c5750670f43fc2c04ee000083125b1561268357600061265c8461276d565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612691565b8161268d846128a6565b0290505b670de0b6b3a764000090056126df7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc000082128015906126d8575068070c1cc73b00c800008213155b6008611fb8565b6126e881612c46565b9695505050505050565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fd5b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401907fffffffffffffffffffffffffffffffffff3f68318436f8ea4cb460f000000000850102816127b957fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f820581019050806002029450505050505b919050565b6000670de0b6b3a76400008212156128e3576128d9826ec097ce7bc90715b34b9f1000000000816128d357fe5b056128a6565b60000390506128a1565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261293457770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261296c576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126129b4576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126129ef576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf8508312612a2657693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e28312612a5d57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d038312612a925768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb417461211108312612abd57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d8312612af2576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312612b27576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312612b5b576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac8312612b8f576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d631000008086030281612bb257fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000612c8b7ffffffffffffffffffffffffffffffffffffffffffffffffdc702bd3a30fc00008312158015612c84575068070c1cc73b00c800008313155b6009611fb8565b6000821215612cbf57612ca082600003612c46565b6ec097ce7bc90715b34b9f100000000081612cb757fe5b0590506128a1565b60006806f05b59d3b20000008312612d1557507ffffffffffffffffffffffffffffffffffffffffffffffff90fa4a62c4e00000090910190770195e54c5dd42177f53a27172fa9ec630262827000000000612d61565b6803782dace9d90000008312612d5d57507ffffffffffffffffffffffffffffffffffffffffffffffffc87d2531627000000909101906b1425982cf597cd205cef7380612d61565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412612dc7577fffffffffffffffffffffffffffffffffffffffffffffff5287143a539e0000009093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412612e19577fffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf0000009093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412612e69577fffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e78000009093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412612eb9577fffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c000009093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412612f08577ffffffffffffffffffffffffffffffffffffffffffffffff5287143a539e000009093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412612f57577ffffffffffffffffffffffffffffffffffffffffffffffffa9438a1d29cf000009093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412612fa6577ffffffffffffffffffffffffffffffffffffffffffffffffd4a1c50e94e7800009093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412612ff5577ffffffffffffffffffffffffffffffffffffffffffffffffea50e2874a73c00009093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d6310000084840205850205969550505050505056fea264697066735822122092f5a8f0d4c4f6dd2b5bcc4417c23e8281ce30d7b8be1b4a8648ae94e29bae8164736f6c63430007010033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$6,529.06
Net Worth in FRAX
6,743.801975
Token Allocations
BAL
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| GNO | 100.00% | $0.497123 | 13,133.6925 | $6,529.06 |
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.