Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 231 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Join Pool Via Ag... | 300842728 | 368 days ago | IN | 0 ETH | 0.00000906 | ||||
| Join Pool Via Ag... | 300842499 | 368 days ago | IN | 0 ETH | 0.000009 | ||||
| Join Pool Via Ag... | 298113031 | 376 days ago | IN | 0 ETH | 0.00001169 | ||||
| Join Pool Via Ag... | 273841464 | 446 days ago | IN | 0 ETH | 0.00001944 | ||||
| Join Pool Via Ag... | 273373349 | 448 days ago | IN | 0 ETH | 0.0000625 | ||||
| Join Pool Via Ag... | 273333859 | 448 days ago | IN | 0 ETH | 0.00004887 | ||||
| Join Pool Via Ag... | 273333737 | 448 days ago | IN | 0 ETH | 0.00003653 | ||||
| Join Pool Via Ag... | 273333592 | 448 days ago | IN | 0 ETH | 0.000032 | ||||
| Join Pool Via Ag... | 273311201 | 448 days ago | IN | 0 ETH | 0.00002698 | ||||
| Join Pool Via Ag... | 273311012 | 448 days ago | IN | 0 ETH | 0.00001318 | ||||
| Join Pool Via Ag... | 273310917 | 448 days ago | IN | 0 ETH | 0.0000211 | ||||
| Join Pool Via Ag... | 271352224 | 454 days ago | IN | 0.0001 ETH | 0.00000806 | ||||
| Join Pool Via Ag... | 267319021 | 465 days ago | IN | 0.03956 ETH | 0.00000567 | ||||
| Join Pool Via Ag... | 252113810 | 510 days ago | IN | 0 ETH | 0.00000554 | ||||
| Join Pool Via Ag... | 249445579 | 518 days ago | IN | 0.0001 ETH | 0.00000592 | ||||
| Transfer | 249441022 | 518 days ago | IN | 0 ETH | 0.00000047 | ||||
| Join Pool Via Ag... | 249435346 | 518 days ago | IN | 0 ETH | 0.00000669 | ||||
| Transfer | 249432293 | 518 days ago | IN | 0 ETH | 0.00000097 | ||||
| Transfer | 249423518 | 518 days ago | IN | 0 ETH | 0.00000038 | ||||
| Join Pool Via Ag... | 223709022 | 592 days ago | IN | 0.0001 ETH | 0.00000505 | ||||
| Join Pool Via Ag... | 223516809 | 593 days ago | IN | 0.036 ETH | 0.00000694 | ||||
| Join Pool Via Ag... | 223516718 | 593 days ago | IN | 0.04 ETH | 0.00000671 | ||||
| Join Pool Via Ag... | 223516704 | 593 days ago | IN | 0.022 ETH | 0.00000671 | ||||
| Join Pool Via Ag... | 223516555 | 593 days ago | IN | 0.03 ETH | 0.00001165 | ||||
| Join Pool Via Ag... | 223516427 | 593 days ago | IN | 0.065 ETH | 0.00000996 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 271352224 | 454 days ago | 0.0001 ETH | ||||
| 267319021 | 465 days ago | 2 wei | ||||
| 267319021 | 465 days ago | 2 wei | ||||
| 267319021 | 465 days ago | 0.03956 ETH | ||||
| 252113810 | 510 days ago | 1 wei | ||||
| 252113810 | 510 days ago | 1 wei | ||||
| 249445579 | 518 days ago | 0.00010094 ETH | ||||
| 249445579 | 518 days ago | 0.00010094 ETH | ||||
| 249445579 | 518 days ago | 0.0001 ETH | ||||
| 223709022 | 592 days ago | 7 wei | ||||
| 223709022 | 592 days ago | 7 wei | ||||
| 223709022 | 592 days ago | 0.0001 ETH | ||||
| 223516809 | 593 days ago | 0.0000141 ETH | ||||
| 223516809 | 593 days ago | 0.0000141 ETH | ||||
| 223516809 | 593 days ago | 0.036 ETH | ||||
| 223516718 | 593 days ago | 0.00001444 ETH | ||||
| 223516718 | 593 days ago | 0.00001444 ETH | ||||
| 223516718 | 593 days ago | 0.04 ETH | ||||
| 223516704 | 593 days ago | 0.00000934 ETH | ||||
| 223516704 | 593 days ago | 0.00000934 ETH | ||||
| 223516704 | 593 days ago | 0.022 ETH | ||||
| 223516555 | 593 days ago | 0.0000059 ETH | ||||
| 223516555 | 593 days ago | 0.0000059 ETH | ||||
| 223516555 | 593 days ago | 0.03 ETH | ||||
| 223516427 | 593 days ago | 0.0001234 ETH |
Cross-Chain Transactions
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 Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or 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 Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
s███
██████
@██████
,s███`
,██████████████
█████████^@█████_
██████████_ 7@███_ "█████████M
@██████████_ `_ "@█████b
^^^^^^^^^^" ^"`
████████████████████p _█████████████████████
@████████████████████ @███████████WT@██████b
████████████████████ @███████████ ,██████
@███████████████████ @███████████████████b
@██████████████████ @██████████████████b
"█████████████████ @█████████████████b
@███████████████ @████████████████
%█████████████ @██████████████`
^%██████████ @███████████"
████████ @██████W"`
1███████
"@█████
7W@█
*/
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@swaap-labs/v2-errors/contracts/SwaapV2Errors.sol";
import "@swaap-labs/v2-interfaces/contracts/standalone-utils/IProxyJoinViaAggregator.sol";
import "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/openzeppelin/IERC20Permit.sol";
import "@balancer-labs/v2-interfaces/contracts/vault/IBasePool.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/Ownable.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ReentrancyGuard.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/SafeERC20.sol";
import "@balancer-labs/v2-solidity-utils/contracts/helpers/ScalingHelpers.sol";
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/misc/IWETH.sol";
import "@balancer-labs/v2-pool-utils/contracts/BasePoolAuthorization.sol";
import "@openzeppelin/contracts-v0.7/utils/Pausable.sol";
import "@openzeppelin/contracts-v0.7/utils/Address.sol";
/**
* @title ProxyJoinViaAggregator
* @author Swaap-labs (https://github.com/swaap-labs/swaap-v2-monorepo)
* @notice Proxy that enables to swap tokens with aggregators before joining a pool.
*/
contract ProxyJoinViaAggregator is BasePoolAuthorization, ReentrancyGuard, Pausable, IProxyJoinViaAggregator {
using FixedPoint for uint256;
using SafeERC20 for IERC20;
using Address for address payable;
modifier beforeDeadline(uint256 deadline) {
_srequire(block.timestamp <= deadline, SwaapV2Errors.PASSED_DEADLINE);
_;
}
address constant private NATIVE_ADDRESS = address(0);
uint256 constant private ONE = 10 ** 18;
IVault immutable public vault;
IWETH immutable public weth;
address immutable public zeroEx;
address immutable public paraswap;
address immutable public oneInch;
address immutable public odos;
constructor(address _vault, IWETH _weth, address _zeroEx, address _paraswap, address _oneInch, address _odos)
BasePoolAuthorization(_DELEGATE_OWNER)
Authentication(bytes20(address(this)))
{
vault = IVault(_vault);
weth = _weth;
zeroEx = _zeroEx;
paraswap = _paraswap;
oneInch = _oneInch;
odos = _odos;
}
/// @inheritdoc IProxyJoinViaAggregator
function permitJoinPoolViaAggregator(
bytes32 poolId,
IVault.JoinPoolRequest calldata request,
Quote[] calldata fillQuotes,
IERC20[] calldata joiningAssets,
uint256[] calldata joiningAmounts,
PermitToken[] calldata permitTokens,
uint256 minBptAmountOut,
uint256 deadline
)
external payable override
whenNotPaused
nonReentrant
beforeDeadline(deadline)
returns (uint256 bptAmountOut)
{
_permitERC20s(permitTokens);
return _joinPoolViaAggregator(
poolId,
request,
fillQuotes,
joiningAssets,
joiningAmounts,
minBptAmountOut
);
}
function _permitERC20s(PermitToken[] calldata permitTokens) internal {
// If permitData is empty, skip the permit call
for(uint256 i; i < permitTokens.length; ++i) {
_permitERC20(permitTokens[i].token, permitTokens[i].permitData);
}
}
function _permitERC20(IERC20 joiningAsset, bytes calldata permitData) internal {
// If permitData is empty, skip the permit call
_srequire(permitData.length == 224, SwaapV2Errors.INVALID_DATA_LENGTH);
(bool success, bytes memory returnData) = address(joiningAsset).call(
abi.encodePacked(
IERC20Permit.permit.selector,
permitData
)
);
if(!success) {
assembly {
revert(add(returnData, 32), mload(returnData))
}
}
}
/// @inheritdoc IProxyJoinViaAggregator
function joinPoolViaAggregator(
bytes32 poolId,
IVault.JoinPoolRequest memory request,
Quote[] calldata fillQuotes,
IERC20[] calldata joiningAssets,
uint256[] calldata joiningAmounts,
uint256 minBptAmountOut,
uint256 deadline
)
external payable override
whenNotPaused
nonReentrant
beforeDeadline(deadline)
returns (uint256 bptAmountOut)
{
return _joinPoolViaAggregator(
poolId,
request,
fillQuotes,
joiningAssets,
joiningAmounts,
minBptAmountOut
);
}
function _joinPoolViaAggregator(
bytes32 poolId,
IVault.JoinPoolRequest memory request,
Quote[] calldata fillQuotes,
IERC20[] calldata joiningAssets,
uint256[] calldata joiningAmounts,
uint256 minBptAmountOut
) internal returns (uint256 bptAmountOut) {
_transferFromMultipleAssets(joiningAssets, joiningAmounts);
_tradeAssetsExternally(fillQuotes);
// The vault will make sure that the tokens are the same as the pool
(IERC20[] memory poolTokens,uint256[] memory poolBalances,) = vault.getPoolTokens(poolId);
bptAmountOut = _getMaximumPoolShares(_getPoolAddress(poolId), poolTokens, poolBalances, request);
_srequire(bptAmountOut >= minBptAmountOut, SwaapV2Errors.MIN_BALANCE_OUT_NOT_MET);
_injectPoolSharesOut(request.userData, bptAmountOut);
_ensureVaultAllowances(poolTokens, request.maxAmountsIn);
_joinPool(bptAmountOut, poolId, request);
_handleRemainingTokens(poolTokens, joiningAssets);
return bptAmountOut;
}
function _joinPool(
uint256 expectedBptAmountOut,
bytes32 poolId,
IVault.JoinPoolRequest memory request
) internal {
address poolAddress = _getPoolAddress(poolId);
uint256 prevBptBalance = IERC20(poolAddress).balanceOf(msg.sender);
vault.joinPool(
poolId,
address(this),
msg.sender,
request
);
uint256 afterBptBalance = IERC20(poolAddress).balanceOf(msg.sender);
_srequire(afterBptBalance.sub(prevBptBalance) >= expectedBptAmountOut, SwaapV2Errors.MIN_BALANCE_OUT_NOT_MET);
}
function _transferFromMultipleAssets(IERC20[] memory assets, uint256[] memory amounts) internal {
// for gas optimization purposes we convert all native token
// to wrapped native because the vault will do it anyways and
// most likely the other exchanges will wrap it too
// ensure length of joiningAssets and joiningAmounts are the same
uint256 length = assets.length;
InputHelpers.ensureInputLengthMatch(length, amounts.length);
for(uint256 i; i < length; ++i) {
transferFromAll(assets[i], amounts[i]);
}
}
function _getExpectedPoolShares(bytes memory userData) internal pure returns (uint256 expectedPoolShares) {
(, expectedPoolShares) = abi.decode(userData, (uint8, uint256));
}
function _handleRemainingTokens(
IERC20[] memory poolTokens,
IERC20[] memory joiningAssets
) internal {
for(uint256 i; i < joiningAssets.length; ++i) {
IERC20 joiningAsset = joiningAssets[i];
transferAll(joiningAsset, getBalance(joiningAsset));
}
for(uint256 i; i < poolTokens.length; ++i) {
IERC20 poolToken = poolTokens[i];
transferAll(poolToken, getBalance(poolToken));
}
}
function _tradeAssetsExternally(
Quote[] calldata fillQuotes
) internal {
for(uint256 i; i < fillQuotes.length; ++i) {
Quote memory quote = fillQuotes[i];
if(quote.targetAggregator == zeroEx) {
_tradeWithAggregator(zeroEx, quote);
} else if(quote.targetAggregator == paraswap) {
_tradeWithAggregator(paraswap, quote);
} else if(quote.targetAggregator == oneInch) {
_tradeWithAggregator(oneInch, quote);
} else if(quote.targetAggregator == odos) {
_tradeWithAggregator(odos, quote);
} else {
_srevert(SwaapV2Errors.INVALID_AGGREGATOR);
}
}
}
function _tradeWithAggregator(
address aggregator,
Quote memory quote
) private {
IERC20 sellToken = isNative(quote.sellToken)? weth : quote.sellToken;
IERC20 buyToken = isNative(quote.buyToken)? weth : quote.buyToken;
uint256 prevSellBalance = getBalance(sellToken);
uint256 prevBuyBalance = getBalance(buyToken);
_srequire(buyToken != sellToken, SwaapV2Errors.SAME_TOKENS);
_getApproval(sellToken, quote.spender, quote.sellAmount);
_performExternalCall(aggregator, quote.quoteCallData);
uint256 soldAmount = prevSellBalance.sub(getBalance(sellToken));
uint256 boughtAmount = getBalance(buyToken).sub(prevBuyBalance);
_srequire(soldAmount <= quote.sellAmount, SwaapV2Errors.EXCEEDED_SWAP_AMOUNT_IN);
_srequire(boughtAmount >= quote.buyAmount, SwaapV2Errors.MIN_BALANCE_OUT_NOT_MET);
}
function _performExternalCall(
address target,
bytes memory data
) private returns (bytes memory) {
bytes32 selector;
assembly {
selector := mload(add(data, 0x20))
}
require(bytes4(selector) != IERC20.transferFrom.selector, "transferFrom not allowed for externalCall");
(bool success, bytes memory returnData) = target.call(data);
if(!success) {
assembly {
revert(add(data, 32), mload(returnData))
}
}
return returnData;
}
function _ensureVaultAllowances(
IERC20[] memory poolTokens,
uint256[] memory maxAmountsIn
) internal {
uint256 length = poolTokens.length;
InputHelpers.ensureInputLengthMatch(length, maxAmountsIn.length);
for(uint256 i; i < length; ++i) {
_getApproval(poolTokens[i], address(vault), maxAmountsIn[i]);
}
}
// calculates the maximum amount of pool shares that can be received and modifies the maxAmountsIn array
function _getMaximumPoolShares(
address pool,
IERC20[] memory poolTokens,
uint256[] memory poolBalances,
IVault.JoinPoolRequest memory request // must be in the same order as the pool
) internal view
returns (uint256)
{
// verify poolBalances length and maxAmountsIn length
uint256 length = poolBalances.length;
InputHelpers.ensureInputLengthMatch(length, request.maxAmountsIn.length);
// get the proxy balances
uint256[] memory proxyBalances = new uint256[](poolTokens.length);
for(uint256 i; i < length; ++i) {
proxyBalances[i] = getBalance(poolTokens[i]);
}
{
// Get scaling factors
uint256[] memory scalingFactors = IBasePool(pool).getScalingFactors();
// upscale pool balances
_upscaleArray(proxyBalances, scalingFactors);
_upscaleArray(poolBalances, scalingFactors);
}
{
uint256 ratio = type(uint256).max;
for(uint256 i; i < length; ++i) {
uint256 localRatio = FixedPoint.divDown(proxyBalances[i], poolBalances[i]);
if(localRatio < ratio) {
ratio = localRatio;
}
}
uint256 extractablePoolShares = FixedPoint.mulDown(ratio, IERC20(pool).totalSupply());
uint256 expectedPoolShares = _getExpectedPoolShares(request.userData);
uint256 sharesRatio = FixedPoint.divUp(extractablePoolShares, expectedPoolShares);
for(uint256 i; i < length; ++i) {
request.maxAmountsIn[i] = FixedPoint.mulUp(request.maxAmountsIn[i], sharesRatio);
}
return extractablePoolShares;
}
}
// expected userData = [joinKind, poolAmountOut]
function _injectPoolSharesOut(bytes memory userData, uint256 sharesAmountOut) internal pure {
assembly {
mstore(add(userData, 0x40), sharesAmountOut)
}
}
/**
* @dev Returns the address of a Pool's contract.
*
* Due to how Pool IDs are created, this is done with no storage accesses and costs little gas.
*/
function _getPoolAddress(bytes32 poolId) internal pure returns (address) {
// 12 byte logical shift left to remove the nonce and specialization setting. We don't need to mask,
// since the logical shift already sets the upper bits to zero.
return address(uint256(poolId) >> (12 * 8));
}
function transferFromAll(IERC20 token, uint256 amount) internal {
if (isNative(token)) {
// The 'amount' input is not used in the payable case in order to convert all the
// native token to wrapped native token. This is useful in function transferAll where only
// one transfer is needed when a fraction of the wrapped tokens are used.
weth.deposit{value: msg.value}();
} else {
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
}
}
function _getApproval(IERC20 token, address target, uint256 amount) internal {
if (token.allowance(address(this), target) < amount) {
token.safeApprove(target, type(uint256).max);
}
}
function getBalance(IERC20 token) internal view returns (uint256) {
if (isNative(token)) {
return weth.balanceOf(address(this));
} else {
return IERC20(token).balanceOf(address(this));
}
}
function transferAll(IERC20 token, uint256 amount) internal {
if (amount != 0) {
if (isNative(token)) {
IWETH(weth).withdraw(amount);
payable(msg.sender).sendValue(amount);
} else {
IERC20(token).safeTransfer(msg.sender, amount);
}
}
}
receive() external payable {
_require(msg.sender == address(weth), Errors.ETH_TRANSFER);
}
function isNative(IERC20 token) internal pure returns(bool) {
return (address(token) == NATIVE_ADDRESS);
}
// Pause functions
function pause() external authenticate {
_pause();
}
function unpause() external authenticate {
_unpause();
}
// Must impement for BasePoolAuthorization
function _getAuthorizer() internal view override returns (IAuthorizer) {
return vault.getAuthorizer();
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
// solhint-disable
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
* supported.
* Uses the default 'BAL' prefix for the error code
*/
function _require(bool condition, uint256 errorCode) pure {
if (!condition) _revert(errorCode);
}
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
* supported.
*/
function _require(
bool condition,
uint256 errorCode,
bytes3 prefix
) pure {
if (!condition) _revert(errorCode, prefix);
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
* Uses the default 'BAL' prefix for the error code
*/
function _revert(uint256 errorCode) pure {
_revert(errorCode, 0x42414c); // This is the raw byte representation of "BAL"
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
*/
function _revert(uint256 errorCode, bytes3 prefix) pure {
uint256 prefixUint = uint256(uint24(prefix));
// We're going to dynamically create a revert string based on the error code, with the following format:
// 'BAL#{errorCode}'
// where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
//
// We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
// number (8 to 16 bits) than the individual string characters.
//
// The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
// much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
// safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
assembly {
// First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
// range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
// the '0' character.
let units := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let tenths := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let hundreds := add(mod(errorCode, 10), 0x30)
// With the individual characters, we can now construct the full string.
// We first append the '#' character (0x23) to the prefix. In the case of 'BAL', it results in 0x42414c23 ('BAL#')
// Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the
// characters to it, each shifted by a multiple of 8.
// The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
// per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
// array).
let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint)))
let revertReason := shl(200, add(formattedPrefix, add(add(units, shl(8, tenths)), shl(16, hundreds))))
// We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
// message will have the following layout:
// [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]
// The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
// also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// The string length is fixed: 7 characters.
mstore(0x24, 7)
// Finally, the string itself is stored.
mstore(0x44, revertReason)
// Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
// the encoded message is therefore 4 + 32 + 32 + 32 = 100.
revert(0, 100)
}
}
library Errors {
// Math
uint256 internal constant ADD_OVERFLOW = 0;
uint256 internal constant SUB_OVERFLOW = 1;
uint256 internal constant SUB_UNDERFLOW = 2;
uint256 internal constant MUL_OVERFLOW = 3;
uint256 internal constant ZERO_DIVISION = 4;
uint256 internal constant DIV_INTERNAL = 5;
uint256 internal constant X_OUT_OF_BOUNDS = 6;
uint256 internal constant Y_OUT_OF_BOUNDS = 7;
uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
uint256 internal constant INVALID_EXPONENT = 9;
// Input
uint256 internal constant OUT_OF_BOUNDS = 100;
uint256 internal constant UNSORTED_ARRAY = 101;
uint256 internal constant UNSORTED_TOKENS = 102;
uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
uint256 internal constant ZERO_TOKEN = 104;
uint256 internal constant INSUFFICIENT_DATA = 105;
// Shared pools
uint256 internal constant MIN_TOKENS = 200;
uint256 internal constant MAX_TOKENS = 201;
uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
uint256 internal constant MINIMUM_BPT = 204;
uint256 internal constant CALLER_NOT_VAULT = 205;
uint256 internal constant UNINITIALIZED = 206;
uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
uint256 internal constant EXPIRED_PERMIT = 209;
uint256 internal constant NOT_TWO_TOKENS = 210;
uint256 internal constant DISABLED = 211;
// Pools
uint256 internal constant MIN_AMP = 300;
uint256 internal constant MAX_AMP = 301;
uint256 internal constant MIN_WEIGHT = 302;
uint256 internal constant MAX_STABLE_TOKENS = 303;
uint256 internal constant MAX_IN_RATIO = 304;
uint256 internal constant MAX_OUT_RATIO = 305;
uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
uint256 internal constant INVALID_TOKEN = 309;
uint256 internal constant UNHANDLED_JOIN_KIND = 310;
uint256 internal constant ZERO_INVARIANT = 311;
uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
uint256 internal constant ORACLE_INVALID_INDEX = 315;
uint256 internal constant ORACLE_BAD_SECS = 316;
uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;
uint256 internal constant AMP_ONGOING_UPDATE = 318;
uint256 internal constant AMP_RATE_TOO_HIGH = 319;
uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;
uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;
uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;
uint256 internal constant RELAYER_NOT_CONTRACT = 323;
uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;
uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;
uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;
uint256 internal constant SWAPS_DISABLED = 327;
uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;
uint256 internal constant PRICE_RATE_OVERFLOW = 329;
uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;
uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;
uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;
uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;
uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;
uint256 internal constant OUT_OF_TARGET_RANGE = 335;
uint256 internal constant UNHANDLED_EXIT_KIND = 336;
uint256 internal constant UNAUTHORIZED_EXIT = 337;
uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;
uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;
uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;
uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;
uint256 internal constant INVALID_INITIALIZATION = 342;
uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;
uint256 internal constant FEATURE_DISABLED = 344;
uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;
uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346;
uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347;
uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348;
uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349;
uint256 internal constant MAX_WEIGHT = 350;
uint256 internal constant UNAUTHORIZED_JOIN = 351;
uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352;
uint256 internal constant FRACTIONAL_TARGET = 353;
uint256 internal constant ADD_OR_REMOVE_BPT = 354;
uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355;
uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356;
uint256 internal constant MALICIOUS_QUERY_REVERT = 357;
uint256 internal constant JOINS_EXITS_DISABLED = 358;
// Lib
uint256 internal constant REENTRANCY = 400;
uint256 internal constant SENDER_NOT_ALLOWED = 401;
uint256 internal constant PAUSED = 402;
uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
uint256 internal constant INSUFFICIENT_BALANCE = 406;
uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;
uint256 internal constant CALLER_IS_NOT_OWNER = 426;
uint256 internal constant NEW_OWNER_IS_ZERO = 427;
uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;
uint256 internal constant CALL_TO_NON_CONTRACT = 429;
uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;
uint256 internal constant NOT_PAUSED = 431;
uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;
uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;
uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434;
uint256 internal constant INVALID_OPERATION = 435;
uint256 internal constant CODEC_OVERFLOW = 436;
uint256 internal constant IN_RECOVERY_MODE = 437;
uint256 internal constant NOT_IN_RECOVERY_MODE = 438;
uint256 internal constant INDUCED_FAILURE = 439;
uint256 internal constant EXPIRED_SIGNATURE = 440;
uint256 internal constant MALFORMED_SIGNATURE = 441;
uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442;
uint256 internal constant UNHANDLED_FEE_TYPE = 443;
uint256 internal constant BURN_FROM_ZERO = 444;
// Vault
uint256 internal constant INVALID_POOL_ID = 500;
uint256 internal constant CALLER_NOT_POOL = 501;
uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
uint256 internal constant INVALID_SIGNATURE = 504;
uint256 internal constant EXIT_BELOW_MIN = 505;
uint256 internal constant JOIN_ABOVE_MAX = 506;
uint256 internal constant SWAP_LIMIT = 507;
uint256 internal constant SWAP_DEADLINE = 508;
uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
uint256 internal constant INSUFFICIENT_ETH = 516;
uint256 internal constant UNALLOCATED_ETH = 517;
uint256 internal constant ETH_TRANSFER = 518;
uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
uint256 internal constant TOKENS_MISMATCH = 520;
uint256 internal constant TOKEN_NOT_REGISTERED = 521;
uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
uint256 internal constant TOKENS_ALREADY_SET = 523;
uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
uint256 internal constant POOL_NO_TOKENS = 527;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;
// Fees
uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603;
// FeeSplitter
uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700;
// Misc
uint256 internal constant UNIMPLEMENTED = 998;
uint256 internal constant SHOULD_NOT_HAPPEN = 999;
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
interface IAuthentication {
/**
* @dev Returns the action identifier associated with the external function described by `selector`.
*/
function getActionId(bytes4 selector) external view returns (bytes32);
}// 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;
/**
* @dev Interface for the SignatureValidator helper, used to support meta-transactions.
*/
interface ISignaturesValidator {
/**
* @dev Returns the EIP712 domain separator.
*/
function getDomainSeparator() external view returns (bytes32);
/**
* @dev Returns the next nonce used by an address to sign messages.
*/
function getNextNonce(address user) external view returns (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;
/**
* @dev Interface for the TemporarilyPausable helper.
*/
interface ITemporarilyPausable {
/**
* @dev Emitted every time the pause state changes by `_setPaused`.
*/
event PausedStateChanged(bool paused);
/**
* @dev Returns the current paused state.
*/
function getPausedState()
external
view
returns (
bool paused,
uint256 pauseWindowEndTime,
uint256 bufferPeriodEndTime
);
}// 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 "../openzeppelin/IERC20.sol";
/**
* @dev Interface for WETH9.
* See https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol
*/
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}// 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: MIT
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
* given `owner`'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: 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;
/**
* @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero
* address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like
* types.
*
* This concept is unrelated to a Pool's Asset Managers.
*/
interface IAsset {
// solhint-disable-previous-line no-empty-blocks
}// 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;
interface IAuthorizer {
/**
* @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`.
*/
function canPerform(
bytes32 actionId,
address account,
address where
) external view returns (bool);
}// 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;
pragma experimental ABIEncoderV2;
import "./IVault.sol";
import "./IPoolSwapStructs.sol";
/**
* @dev Interface for adding and removing liquidity that all Pool contracts should implement. Note that this is not
* the complete Pool contract interface, as it is missing the swap hooks. Pool contracts should also inherit from
* either IGeneralPool or IMinimalSwapInfoPool
*/
interface IBasePool is IPoolSwapStructs {
/**
* @dev Called by the Vault when a user calls `IVault.joinPool` to add liquidity to this Pool. Returns how many of
* each registered token the user should provide, as well as the amount of protocol fees the Pool owes to the Vault.
* The Vault will then take tokens from `sender` and add them to the Pool's balances, as well as collect
* the reported amount in protocol fees, which the pool should calculate based on `protocolSwapFeePercentage`.
*
* Protocol fees are reported and charged on join events so that the Pool is free of debt whenever new users join.
*
* `sender` is the account performing the join (from which tokens will be withdrawn), and `recipient` is the account
* designated to receive any benefits (typically pool shares). `balances` contains the total balances
* for each token the Pool registered in the Vault, in the same order that `IVault.getPoolTokens` would return.
*
* `lastChangeBlock` is the last block in which *any* of the Pool's registered tokens last changed its total
* balance.
*
* `userData` contains any pool-specific instructions needed to perform the calculations, such as the type of
* join (e.g., proportional given an amount of pool shares, single-asset, multi-asset, etc.)
*
* Contracts implementing this function should check that the caller is indeed the Vault before performing any
* state-changing operations, such as minting pool shares.
*/
function onJoinPool(
bytes32 poolId,
address sender,
address recipient,
uint256[] memory balances,
uint256 lastChangeBlock,
uint256 protocolSwapFeePercentage,
bytes memory userData
) external returns (uint256[] memory amountsIn, uint256[] memory dueProtocolFeeAmounts);
/**
* @dev Called by the Vault when a user calls `IVault.exitPool` to remove liquidity from this Pool. Returns how many
* tokens the Vault should deduct from the Pool's balances, as well as the amount of protocol fees the Pool owes
* to the Vault. The Vault will then take tokens from the Pool's balances and send them to `recipient`,
* as well as collect the reported amount in protocol fees, which the Pool should calculate based on
* `protocolSwapFeePercentage`.
*
* Protocol fees are charged on exit events to guarantee that users exiting the Pool have paid their share.
*
* `sender` is the account performing the exit (typically the pool shareholder), and `recipient` is the account
* to which the Vault will send the proceeds. `balances` contains the total token balances for each token
* the Pool registered in the Vault, in the same order that `IVault.getPoolTokens` would return.
*
* `lastChangeBlock` is the last block in which *any* of the Pool's registered tokens last changed its total
* balance.
*
* `userData` contains any pool-specific instructions needed to perform the calculations, such as the type of
* exit (e.g., proportional given an amount of pool shares, single-asset, multi-asset, etc.)
*
* Contracts implementing this function should check that the caller is indeed the Vault before performing any
* state-changing operations, such as burning pool shares.
*/
function onExitPool(
bytes32 poolId,
address sender,
address recipient,
uint256[] memory balances,
uint256 lastChangeBlock,
uint256 protocolSwapFeePercentage,
bytes memory userData
) external returns (uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts);
/**
* @dev Returns this Pool's ID, used when interacting with the Vault (to e.g. join the Pool or swap with it).
*/
function getPoolId() external view returns (bytes32);
/**
* @dev Returns the current swap fee percentage as a 18 decimal fixed point number, so e.g. 1e17 corresponds to a
* 10% swap fee.
*/
function getSwapFeePercentage() external view returns (uint256);
/**
* @dev Returns the scaling factors of each of the Pool's tokens. This is an implementation detail that is typically
* not relevant for outside parties, but which might be useful for some types of Pools.
*/
function getScalingFactors() external view returns (uint256[] memory);
function queryJoin(
bytes32 poolId,
address sender,
address recipient,
uint256[] memory balances,
uint256 lastChangeBlock,
uint256 protocolSwapFeePercentage,
bytes memory userData
) external returns (uint256 bptOut, uint256[] memory amountsIn);
function queryExit(
bytes32 poolId,
address sender,
address recipient,
uint256[] memory balances,
uint256 lastChangeBlock,
uint256 protocolSwapFeePercentage,
bytes memory userData
) external returns (uint256 bptIn, uint256[] memory 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 <0.9.0;
// Inspired by Aave Protocol's IFlashLoanReceiver.
import "../solidity-utils/openzeppelin/IERC20.sol";
interface IFlashLoanRecipient {
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external;
}// 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;
pragma experimental ABIEncoderV2;
import "../solidity-utils/openzeppelin/IERC20.sol";
import "./IVault.sol";
interface IPoolSwapStructs {
// This is not really an interface - it just defines common structs used by other interfaces: IGeneralPool and
// IMinimalSwapInfoPool.
//
// This data structure represents a request for a token swap, where `kind` indicates the swap type ('given in' or
// 'given out') which indicates whether or not the amount sent by the pool is known.
//
// The pool receives `tokenIn` and sends `tokenOut`. `amount` is the number of `tokenIn` tokens the pool will take
// in, or the number of `tokenOut` tokens the Pool will send out, depending on the given swap `kind`.
//
// All other fields are not strictly necessary for most swaps, but are provided to support advanced scenarios in
// some Pools.
//
// `poolId` is the ID of the Pool involved in the swap - this is useful for Pool contracts that implement more than
// one Pool.
//
// The meaning of `lastChangeBlock` depends on the Pool specialization:
// - Two Token or Minimal Swap Info: the last block in which either `tokenIn` or `tokenOut` changed its total
// balance.
// - General: the last block in which *any* of the Pool's registered tokens changed its total balance.
//
// `from` is the origin address for the funds the Pool receives, and `to` is the destination address
// where the Pool sends the outgoing tokens.
//
// `userData` is extra data provided by the caller - typically a signature from a trusted party.
struct SwapRequest {
IVault.SwapKind kind;
IERC20 tokenIn;
IERC20 tokenOut;
uint256 amount;
// Misc data
bytes32 poolId;
uint256 lastChangeBlock;
address from;
address to;
bytes 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;
pragma experimental ABIEncoderV2;
import "../solidity-utils/openzeppelin/IERC20.sol";
import "./IVault.sol";
import "./IAuthorizer.sol";
interface IProtocolFeesCollector {
event SwapFeePercentageChanged(uint256 newSwapFeePercentage);
event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage);
function withdrawCollectedFees(
IERC20[] calldata tokens,
uint256[] calldata amounts,
address recipient
) external;
function setSwapFeePercentage(uint256 newSwapFeePercentage) external;
function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external;
function getSwapFeePercentage() external view returns (uint256);
function getFlashLoanFeePercentage() external view returns (uint256);
function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts);
function getAuthorizer() external view returns (IAuthorizer);
function vault() external view returns (IVault);
}// 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 experimental ABIEncoderV2;
import "../solidity-utils/openzeppelin/IERC20.sol";
import "../solidity-utils/helpers/IAuthentication.sol";
import "../solidity-utils/helpers/ISignaturesValidator.sol";
import "../solidity-utils/helpers/ITemporarilyPausable.sol";
import "../solidity-utils/misc/IWETH.sol";
import "./IAsset.sol";
import "./IAuthorizer.sol";
import "./IFlashLoanRecipient.sol";
import "./IProtocolFeesCollector.sol";
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Full external interface for the Vault core contract - no external or public methods exist in the contract that
* don't override one of these declarations.
*/
interface IVault is ISignaturesValidator, ITemporarilyPausable, IAuthentication {
// Generalities about the Vault:
//
// - Whenever documentation refers to 'tokens', it strictly refers to ERC20-compliant token contracts. Tokens are
// transferred out of the Vault by calling the `IERC20.transfer` function, and transferred in by calling
// `IERC20.transferFrom`. In these cases, the sender must have previously allowed the Vault to use their tokens by
// calling `IERC20.approve`. The only deviation from the ERC20 standard that is supported is functions not returning
// a boolean value: in these scenarios, a non-reverting call is assumed to be successful.
//
// - All non-view functions in the Vault are non-reentrant: calling them while another one is mid-execution (e.g.
// while execution control is transferred to a token contract during a swap) will result in a revert. View
// functions can be called in a re-reentrant way, but doing so might cause them to return inconsistent results.
// Contracts calling view functions in the Vault must make sure the Vault has not already been entered.
//
// - View functions revert if referring to either unregistered Pools, or unregistered tokens for registered Pools.
// Authorizer
//
// Some system actions are permissioned, like setting and collecting protocol fees. This permissioning system exists
// outside of the Vault in the Authorizer contract: the Vault simply calls the Authorizer to check if the caller
// can perform a given action.
/**
* @dev Returns the Vault's Authorizer.
*/
function getAuthorizer() external view returns (IAuthorizer);
/**
* @dev Sets a new Authorizer for the Vault. The caller must be allowed by the current Authorizer to do this.
*
* Emits an `AuthorizerChanged` event.
*/
function setAuthorizer(IAuthorizer newAuthorizer) external;
/**
* @dev Emitted when a new authorizer is set by `setAuthorizer`.
*/
event AuthorizerChanged(IAuthorizer indexed newAuthorizer);
// Relayers
//
// Additionally, it is possible for an account to perform certain actions on behalf of another one, using their
// Vault ERC20 allowance and Internal Balance. These accounts are said to be 'relayers' for these Vault functions,
// and are expected to be smart contracts with sound authentication mechanisms. For an account to be able to wield
// this power, two things must occur:
// - The Authorizer must grant the account the permission to be a relayer for the relevant Vault function. This
// means that Balancer governance must approve each individual contract to act as a relayer for the intended
// functions.
// - Each user must approve the relayer to act on their behalf.
// This double protection means users cannot be tricked into approving malicious relayers (because they will not
// have been allowed by the Authorizer via governance), nor can malicious relayers approved by a compromised
// Authorizer or governance drain user funds, since they would also need to be approved by each individual user.
/**
* @dev Returns true if `user` has approved `relayer` to act as a relayer for them.
*/
function hasApprovedRelayer(address user, address relayer) external view returns (bool);
/**
* @dev Allows `relayer` to act as a relayer for `sender` if `approved` is true, and disallows it otherwise.
*
* Emits a `RelayerApprovalChanged` event.
*/
function setRelayerApproval(
address sender,
address relayer,
bool approved
) external;
/**
* @dev Emitted every time a relayer is approved or disapproved by `setRelayerApproval`.
*/
event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved);
// Internal Balance
//
// Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later
// transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination
// when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced
// gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users.
//
// Internal Balance management features batching, which means a single contract call can be used to perform multiple
// operations of different kinds, with different senders and recipients, at once.
/**
* @dev Returns `user`'s Internal Balance for a set of tokens.
*/
function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory);
/**
* @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)
* and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as
* it lets integrators reuse a user's Vault allowance.
*
* For each operation, if the caller is not `sender`, it must be an authorized relayer for them.
*/
function manageUserBalance(UserBalanceOp[] memory ops) external payable;
/**
* @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received
without manual WETH wrapping or unwrapping.
*/
struct UserBalanceOp {
UserBalanceOpKind kind;
IAsset asset;
uint256 amount;
address sender;
address payable recipient;
}
// There are four possible operations in `manageUserBalance`:
//
// - DEPOSIT_INTERNAL
// Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding
// `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`.
//
// ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped
// and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is
// relevant for relayers).
//
// Emits an `InternalBalanceChanged` event.
//
//
// - WITHDRAW_INTERNAL
// Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`.
//
// ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send
// it to the recipient as ETH.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_INTERNAL
// Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_EXTERNAL
// Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by
// relayers, as it lets them reuse a user's Vault allowance.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `ExternalBalanceTransfer` event.
enum UserBalanceOpKind { DEPOSIT_INTERNAL, WITHDRAW_INTERNAL, TRANSFER_INTERNAL, TRANSFER_EXTERNAL }
/**
* @dev Emitted when a user's Internal Balance changes, either from calls to `manageUserBalance`, or through
* interacting with Pools using Internal Balance.
*
* Because Internal Balance works exclusively with ERC20 tokens, ETH deposits and withdrawals will use the WETH
* address.
*/
event InternalBalanceChanged(address indexed user, IERC20 indexed token, int256 delta);
/**
* @dev Emitted when a user's Vault ERC20 allowance is used by the Vault to transfer tokens to an external account.
*/
event ExternalBalanceTransfer(IERC20 indexed token, address indexed sender, address recipient, uint256 amount);
// Pools
//
// There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced
// functionality:
//
// - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the
// balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads),
// which increase with the number of registered tokens.
//
// - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the
// balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted
// constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are
// independent of the number of registered tokens.
//
// - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like
// minimal swap info Pools, these are called via IMinimalSwapInfoPool.
enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN }
/**
* @dev Registers the caller account as a Pool with a given specialization setting. Returns the Pool's ID, which
* is used in all Pool-related functions. Pools cannot be deregistered, nor can the Pool's specialization be
* changed.
*
* The caller is expected to be a smart contract that implements either `IGeneralPool` or `IMinimalSwapInfoPool`,
* depending on the chosen specialization setting. This contract is known as the Pool's contract.
*
* Note that the same contract may register itself as multiple Pools with unique Pool IDs, or in other words,
* multiple Pools may share the same contract.
*
* Emits a `PoolRegistered` event.
*/
function registerPool(PoolSpecialization specialization) external returns (bytes32);
/**
* @dev Emitted when a Pool is registered by calling `registerPool`.
*/
event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, PoolSpecialization specialization);
/**
* @dev Returns a Pool's contract address and specialization setting.
*/
function getPool(bytes32 poolId) external view returns (address, PoolSpecialization);
/**
* @dev Registers `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Pools can only interact with tokens they have registered. Users join a Pool by transferring registered tokens,
* exit by receiving registered tokens, and can only swap registered tokens.
*
* Each token can only be registered once. For Pools with the Two Token specialization, `tokens` must have a length
* of two, that is, both tokens must be registered in the same `registerTokens` call, and they must be sorted in
* ascending order.
*
* The `tokens` and `assetManagers` arrays must have the same length, and each entry in these indicates the Asset
* Manager for the corresponding token. Asset Managers can manage a Pool's tokens via `managePoolBalance`,
* depositing and withdrawing them directly, and can even set their balance to arbitrary amounts. They are therefore
* expected to be highly secured smart contracts with sound design principles, and the decision to register an
* Asset Manager should not be made lightly.
*
* Pools can choose not to assign an Asset Manager to a given token by passing in the zero address. Once an Asset
* Manager is set, it cannot be changed except by deregistering the associated token and registering again with a
* different Asset Manager.
*
* Emits a `TokensRegistered` event.
*/
function registerTokens(
bytes32 poolId,
IERC20[] memory tokens,
address[] memory assetManagers
) external;
/**
* @dev Emitted when a Pool registers tokens by calling `registerTokens`.
*/
event TokensRegistered(bytes32 indexed poolId, IERC20[] tokens, address[] assetManagers);
/**
* @dev Deregisters `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Only registered tokens (via `registerTokens`) can be deregistered. Additionally, they must have zero total
* balance. For Pools with the Two Token specialization, `tokens` must have a length of two, that is, both tokens
* must be deregistered in the same `deregisterTokens` call.
*
* A deregistered token can be re-registered later on, possibly with a different Asset Manager.
*
* Emits a `TokensDeregistered` event.
*/
function deregisterTokens(bytes32 poolId, IERC20[] memory tokens) external;
/**
* @dev Emitted when a Pool deregisters tokens by calling `deregisterTokens`.
*/
event TokensDeregistered(bytes32 indexed poolId, IERC20[] tokens);
/**
* @dev Returns detailed information for a Pool's registered token.
*
* `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens
* withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token`
* equals the sum of `cash` and `managed`.
*
* Internally, `cash` and `managed` are stored using 112 bits. No action can ever cause a Pool's token `cash`,
* `managed` or `total` balance to be greater than 2^112 - 1.
*
* `lastChangeBlock` is the number of the block in which `token`'s total balance was last modified (via either a
* join, exit, swap, or Asset Manager update). This value is useful to avoid so-called 'sandwich attacks', for
* example when developing price oracles. A change of zero (e.g. caused by a swap with amount zero) is considered a
* change for this purpose, and will update `lastChangeBlock`.
*
* `assetManager` is the Pool's token Asset Manager.
*/
function getPoolTokenInfo(bytes32 poolId, IERC20 token)
external
view
returns (
uint256 cash,
uint256 managed,
uint256 lastChangeBlock,
address assetManager
);
/**
* @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of
* the tokens' `balances` changed.
*
* The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all
* Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.
*
* If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same
* order as passed to `registerTokens`.
*
* Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are
* the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`
* instead.
*/
function getPoolTokens(bytes32 poolId)
external
view
returns (
IERC20[] memory tokens,
uint256[] memory balances,
uint256 lastChangeBlock
);
/**
* @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will
* trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized
* Pool shares.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount
* to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces
* these maximums.
*
* If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable
* this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the
* WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent
* back to the caller (not the sender, which is important for relayers).
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be
* sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final
* `assets` array might not be sorted. Pools with no registered tokens cannot be joined.
*
* If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only
* be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be
* withdrawn from Internal Balance: attempting to do so will trigger a revert.
*
* This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed
* directly to the Pool's contract, as is `recipient`.
*
* Emits a `PoolBalanceChanged` event.
*/
function joinPool(
bytes32 poolId,
address sender,
address recipient,
JoinPoolRequest memory request
) external payable;
struct JoinPoolRequest {
IAsset[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
/**
* @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will
* trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized
* Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see
* `getPoolTokenInfo`).
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum
* token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:
* it just enforces these minimums.
*
* If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To
* enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead
* of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must
* be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the
* final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.
*
* If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,
* an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to
* do so will trigger a revert.
*
* `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the
* `tokens` array. This array must match the Pool's registered tokens.
*
* This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and
* passed directly to the Pool's contract.
*
* Emits a `PoolBalanceChanged` event.
*/
function exitPool(
bytes32 poolId,
address sender,
address payable recipient,
ExitPoolRequest memory request
) external;
struct ExitPoolRequest {
IAsset[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
/**
* @dev Emitted when a user joins or exits a Pool by calling `joinPool` or `exitPool`, respectively.
*/
event PoolBalanceChanged(
bytes32 indexed poolId,
address indexed liquidityProvider,
IERC20[] tokens,
int256[] deltas,
uint256[] protocolFeeAmounts
);
enum PoolBalanceChangeKind { JOIN, EXIT }
// Swaps
//
// Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,
// they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be
// aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.
//
// The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.
// In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),
// and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').
// More complex swaps, such as one token in to multiple tokens out can be achieved by batching together
// individual swaps.
//
// There are two swap kinds:
// - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the
// `onSwap` hook) the amount of tokens out (to send to the recipient).
// - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines
// (via the `onSwap` hook) the amount of tokens in (to receive from the sender).
//
// Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with
// the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated
// tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended
// swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at
// the final intended token.
//
// In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal
// Balance) after all individual swaps have been completed, and the net token balance change computed. This makes
// certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost
// much less gas than they would otherwise.
//
// It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple
// Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only
// updating the Pool's internal accounting).
//
// To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token
// involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the
// minimum amount of tokens to receive (by passing a negative value) is specified.
//
// Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after
// this point in time (e.g. if the transaction failed to be included in a block promptly).
//
// If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do
// the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be
// passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the
// same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).
//
// Finally, Internal Balance can be used when either sending or receiving tokens.
enum SwapKind { GIVEN_IN, GIVEN_OUT }
/**
* @dev Performs a swap with a single Pool.
*
* If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
* taken from the Pool, which must be greater than or equal to `limit`.
*
* If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
* sent to the Pool, which must be less than or equal to `limit`.
*
* Internal Balance usage and the recipient are determined by the `funds` struct.
*
* Emits a `Swap` event.
*/
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IAsset assetIn;
IAsset assetOut;
uint256 amount;
bytes userData;
}
/**
* @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
* the amount of tokens sent to or received from the Pool, depending on the `kind` value.
*
* Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
* Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
* the same index in the `assets` array.
*
* Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
* Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
* `amountOut` depending on the swap kind.
*
* Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
* of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
* the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
*
* The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
* or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
* out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
* or unwrapped from WETH by the Vault.
*
* Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
* the minimum or maximum amount of each token the vault is allowed to transfer.
*
* `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
* equivalent `swap` call.
*
* Emits `Swap` events.
*/
function batchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) external payable returns (int256[] memory);
/**
* @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
* `assets` array passed to that function, and ETH assets are converted to WETH.
*
* If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
* from the previous swap, depending on the swap kind.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
/**
* @dev Emitted for each individual swap performed by `swap` or `batchSwap`.
*/
event Swap(
bytes32 indexed poolId,
IERC20 indexed tokenIn,
IERC20 indexed tokenOut,
uint256 amountIn,
uint256 amountOut
);
/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
/**
* @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be
* simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.
*
* Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)
* the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it
* receives are the same that an equivalent `batchSwap` call would receive.
*
* Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.
* This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,
* approve them for the Vault, or even know a user's address.
*
* Note that this function is not 'view' (due to implementation details): the client code must explicitly execute
* eth_call instead of eth_sendTransaction.
*/
function queryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds
) external returns (int256[] memory assetDeltas);
// Flash Loans
/**
* @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
* and then reverting unless the tokens plus a proportional protocol fee have been returned.
*
* The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
* for each token contract. `tokens` must be sorted in ascending order.
*
* The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
* `receiveFlashLoan` call.
*
* Emits `FlashLoan` events.
*/
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/
event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);
// Asset Management
//
// Each token registered for a Pool can be assigned an Asset Manager, which is able to freely withdraw the Pool's
// tokens from the Vault, deposit them, or assign arbitrary values to its `managed` balance (see
// `getPoolTokenInfo`). This makes them extremely powerful and dangerous. Even if an Asset Manager only directly
// controls one of the tokens in a Pool, a malicious manager could set that token's balance to manipulate the
// prices of the other tokens, and then drain the Pool with swaps. The risk of using Asset Managers is therefore
// not constrained to the tokens they are managing, but extends to the entire Pool's holdings.
//
// However, a properly designed Asset Manager smart contract can be safely used for the Pool's benefit,
// for example by lending unused tokens out for interest, or using them to participate in voting protocols.
//
// This concept is unrelated to the IAsset interface.
/**
* @dev Performs a set of Pool balance operations, which may be either withdrawals, deposits or updates.
*
* Pool Balance management features batching, which means a single contract call can be used to perform multiple
* operations of different kinds, with different Pools and tokens, at once.
*
* For each operation, the caller must be registered as the Asset Manager for `token` in `poolId`.
*/
function managePoolBalance(PoolBalanceOp[] memory ops) external;
struct PoolBalanceOp {
PoolBalanceOpKind kind;
bytes32 poolId;
IERC20 token;
uint256 amount;
}
/**
* Withdrawals decrease the Pool's cash, but increase its managed balance, leaving the total balance unchanged.
*
* Deposits increase the Pool's cash, but decrease its managed balance, leaving the total balance unchanged.
*
* Updates don't affect the Pool's cash balance, but because the managed balance changes, it does alter the total.
* The external amount can be either increased or decreased by this call (i.e., reporting a gain or a loss).
*/
enum PoolBalanceOpKind { WITHDRAW, DEPOSIT, UPDATE }
/**
* @dev Emitted when a Pool's token Asset Manager alters its balance via `managePoolBalance`.
*/
event PoolBalanceManaged(
bytes32 indexed poolId,
address indexed assetManager,
IERC20 indexed token,
int256 cashDelta,
int256 managedDelta
);
// Protocol Fees
//
// Some operations cause the Vault to collect tokens in the form of protocol fees, which can then be withdrawn by
// permissioned accounts.
//
// There are two kinds of protocol fees:
//
// - flash loan fees: charged on all flash loans, as a percentage of the amounts lent.
//
// - swap fees: a percentage of the fees charged by Pools when performing swaps. For a number of reasons, including
// swap gas costs and interface simplicity, protocol swap fees are not charged on each individual swap. Rather,
// Pools are expected to keep track of how much they have charged in swap fees, and pay any outstanding debts to the
// Vault when they are joined or exited. This prevents users from joining a Pool with unpaid debt, as well as
// exiting a Pool in debt without first paying their share.
/**
* @dev Returns the current protocol fee module.
*/
function getProtocolFeesCollector() external view returns (IProtocolFeesCollector);
/**
* @dev Safety mechanism to pause most Vault operations in the event of an emergency - typically detection of an
* error in some part of the system.
*
* The Vault can only be paused during an initial time period, after which pausing is forever disabled.
*
* While the contract is paused, the following features are disabled:
* - depositing and transferring internal balance
* - transferring external balance (using the Vault's allowance)
* - swaps
* - joining Pools
* - Asset Manager interactions
*
* Internal Balance can still be withdrawn, and Pools exited.
*/
function setPaused(bool paused) external;
/**
* @dev Returns the Vault's WETH instance.
*/
function WETH() external view returns (IWETH);
// solhint-disable-previous-line func-name-mixedcase
}// 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/vault/IAuthorizer.sol";
import "@balancer-labs/v2-solidity-utils/contracts/helpers/Authentication.sol";
/**
* @dev Base authorization layer implementation for Pools.
*
* The owner account can call some of the permissioned functions - access control of the rest is delegated to the
* Authorizer. Note that this owner is immutable: more sophisticated permission schemes, such as multiple ownership,
* granular roles, etc., could be built on top of this by making the owner a smart contract.
*
* Access control of all other permissioned functions is delegated to an Authorizer. It is also possible to delegate
* control of *all* permissioned functions to the Authorizer by setting the owner address to `_DELEGATE_OWNER`.
*/
abstract contract BasePoolAuthorization is Authentication {
address private immutable _owner;
address internal constant _DELEGATE_OWNER = 0xBA1BA1ba1BA1bA1bA1Ba1BA1ba1BA1bA1ba1ba1B;
constructor(address owner) {
_owner = owner;
}
function getOwner() public view returns (address) {
return _owner;
}
function getAuthorizer() external view returns (IAuthorizer) {
return _getAuthorizer();
}
function _canPerform(bytes32 actionId, address account) internal view override returns (bool) {
if ((getOwner() != _DELEGATE_OWNER) && _isOwnerOnlyAction(actionId)) {
// Only the owner can perform "owner only" actions, unless the owner is delegated.
return msg.sender == getOwner();
} else {
// Non-owner actions are always processed via the Authorizer, as "owner only" ones are when delegated.
return _getAuthorizer().canPerform(actionId, account, address(this));
}
}
function _isOwnerOnlyAction(bytes32) internal view virtual returns (bool) {
return false;
}
function _getAuthorizer() internal view virtual returns (IAuthorizer);
}// 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 "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/IAuthentication.sol";
/**
* @dev Building block for performing access control on external functions.
*
* This contract is used via the `authenticate` modifier (or the `_authenticateCaller` function), which can be applied
* to external functions to only make them callable by authorized accounts.
*
* Derived contracts must implement the `_canPerform` function, which holds the actual access control logic.
*/
abstract contract Authentication is IAuthentication {
bytes32 private immutable _actionIdDisambiguator;
/**
* @dev The main purpose of the `actionIdDisambiguator` is to prevent accidental function selector collisions in
* multi contract systems.
*
* There are two main uses for it:
* - if the contract is a singleton, any unique identifier can be used to make the associated action identifiers
* unique. The contract's own address is a good option.
* - if the contract belongs to a family that shares action identifiers for the same functions, an identifier
* shared by the entire family (and no other contract) should be used instead.
*/
constructor(bytes32 actionIdDisambiguator) {
_actionIdDisambiguator = actionIdDisambiguator;
}
/**
* @dev Reverts unless the caller is allowed to call this function. Should only be applied to external functions.
*/
modifier authenticate() {
_authenticateCaller();
_;
}
/**
* @dev Reverts unless the caller is allowed to call the entry point function.
*/
function _authenticateCaller() internal view {
bytes32 actionId = getActionId(msg.sig);
_require(_canPerform(actionId, msg.sender), Errors.SENDER_NOT_ALLOWED);
}
function getActionId(bytes4 selector) public view override returns (bytes32) {
// Each external function is dynamically assigned an action identifier as the hash of the disambiguator and the
// function selector. Disambiguation is necessary to avoid potential collisions in the function selectors of
// multiple contracts.
return keccak256(abi.encodePacked(_actionIdDisambiguator, selector));
}
function _canPerform(bytes32 actionId, address user) internal view virtual returns (bool);
}// 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
// Based on the Ownable library from OpenZeppelin Contracts, altered to reduce runtime gas by dropping
// support for the GSN.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(msg.sender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_require(owner() == msg.sender, Errors.CALLER_IS_NOT_OWNER);
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
_require(newOwner != address(0), Errors.NEW_OWNER_IS_ZERO);
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// Based on the ReentrancyGuard library from OpenZeppelin Contracts, altered to reduce bytecode size.
// Modifier code is inlined by the compiler, which causes its code to appear multiple times in the codebase. By using
// private functions, we achieve the same end result with slightly higher runtime gas costs, but reduced bytecode size.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_enterNonReentrant();
_;
_exitNonReentrant();
}
function _enterNonReentrant() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
_require(_status != _ENTERED, Errors.REENTRANCY);
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _exitNonReentrant() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// Based on the ReentrancyGuard library from OpenZeppelin Contracts, altered to reduce gas costs.
// The `safeTransfer` and `safeTransferFrom` functions assume that `token` is a contract (an account with code), and
// work differently from the OpenZeppelin version if it is not.
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";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeApprove(
IERC20 token,
address to,
uint256 value
) internal {
// Some contracts need their allowance reduced to 0 before setting it to an arbitrary amount.
if (value != 0 && token.allowance(address(this), address(to)) != 0) {
_callOptionalReturn(address(token), abi.encodeWithSelector(token.approve.selector, to, 0));
}
_callOptionalReturn(address(token), abi.encodeWithSelector(token.approve.selector, to, value));
}
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(address(token), abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(address(token), abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
*
* WARNING: `token` is assumed to be a contract: calls to EOAs will *not* revert.
*/
function _callOptionalReturn(address token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = token.call(data);
// If the low-level call didn't succeed we return whatever was returned from it.
// solhint-disable-next-line no-inline-assembly
assembly {
if eq(success, 0) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
// Finally we check the returndata size is either zero or true - note that this check will always pass for EOAs
_require(returndata.length == 0 || abi.decode(returndata, (bool)), Errors.SAFE_ERC20_CALL_FAILED);
}
}// 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: MIT
pragma solidity >=0.6.2 <0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor () internal {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// 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;
library SwaapV2Errors {
// Safeguard Pool
uint256 internal constant EXCEEDED_SWAP_AMOUNT_IN = 0;
uint256 internal constant EXCEEDED_SWAP_AMOUNT_OUT = 1;
uint256 internal constant UNFAIR_PRICE = 2;
uint256 internal constant LOW_PERFORMANCE = 3;
uint256 internal constant MIN_BALANCE_OUT_NOT_MET = 4;
uint256 internal constant NOT_ENOUGH_PT_OUT = 5;
uint256 internal constant EXCEEDED_BURNED_PT = 6;
uint256 internal constant SIGNER_CANNOT_BE_NULL_ADDRESS = 7;
uint256 internal constant PERFORMANCE_UPDATE_INTERVAL_TOO_LOW = 8;
uint256 internal constant PERFORMANCE_UPDATE_INTERVAL_TOO_HIGH = 9;
uint256 internal constant MAX_PERFORMANCE_DEV_TOO_LOW = 10;
uint256 internal constant MAX_PERFORMANCE_DEV_TOO_HIGH = 11;
uint256 internal constant MAX_TARGET_DEV_TOO_LOW = 12;
uint256 internal constant MAX_TARGET_DEV_TOO_LARGE = 13;
uint256 internal constant MAX_PRICE_DEV_TOO_LOW = 14;
uint256 internal constant MAX_PRICE_DEV_TOO_LARGE = 15;
uint256 internal constant PERFORMANCE_UPDATE_TOO_SOON = 16;
uint256 internal constant BITMAP_SIGNATURE_NOT_VALID = 17;
uint256 internal constant QUOTE_ALREADY_USED = 18;
uint256 internal constant REPLAYABLE_SIGNATURE_NOT_VALID = 19;
uint256 internal constant QUOTE_BALANCE_NO_LONGER_VALID = 20;
uint256 internal constant WRONG_TOKEN_IN_IN_EXCESS = 21;
uint256 internal constant WRONG_TOKEN_OUT_IN_EXCESS = 22;
uint256 internal constant EXCEEDS_TIMEOUT = 23;
uint256 internal constant NON_POSITIVE_PRICE = 24;
uint256 internal constant FEES_TOO_HIGH = 25;
uint256 internal constant LOW_INITIAL_BALANCE = 26;
uint256 internal constant ORACLE_TIMEOUT_TOO_HIGH = 27;
uint256 internal constant OUTDATED_ORACLE_ROUND_ID = 28;
uint256 internal constant LOW_SWAP_AMOUNT_IN = 29;
uint256 internal constant LOW_SWAP_AMOUNT_OUT = 30;
uint256 internal constant PAUSED = 31;
uint256 internal constant INVALID_AGGREGATOR = 32;
uint256 internal constant PASSED_DEADLINE = 33;
uint256 internal constant SAME_TOKENS = 34;
uint256 internal constant INVALID_DATA_LENGTH = 35;
}
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 99 are
* supported.
*/
function _srequire(bool condition, uint256 errorCode) pure {
if (!condition) _srevert(errorCode);
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 99 are supported.
*/
function _srevert(uint256 errorCode) pure {
// We're going to dynamically create a revert uint256 based on the error code, with the following format:
// 'SWAAP#{errorCode}'
// where the code is left-padded with zeroes to two digits (so they range from 00 to 99).
//
// We don't have revert uint256s embedded in the contract to save bytecode size: it takes much less space to store a
// number (8 to 16 bits) than the individual uint256 characters.
//
// The dynamic uint256 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-99
// range, so we only need to convert two 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)
// With the individual characters, we can now construct the full uint256. The SWAAP# part is a known constant
// (0x535741415023): we simply shift this by 16 (to provide space for the 2 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 192 bits (256 minus the length of the uint256, 8 characters * 8
// bits per character = 64) to locate it in the most significant part of the 256 slot (the beginning of a byte
// array).
let revertReason := shl(192, add(0x5357414150230000, add(units, shl(8, tenths))))
// 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 ] [ uint256 location offset ] [ uint256 length ] [ uint256 contents ]
// The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(uint256) function. We
// also write zeroes to the next 29 bytes of memory, but those are about to be overwritten.
mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// Next is the offset to the location of the uint256, which will be placed immediately after (20 bytes away).
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// The uint256 length is fixed: 8 characters.
mstore(0x24, 8)
// Finally, the uint256 itself is stored.
mstore(0x44, revertReason)
// Even if the uint256 is only 8 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)
}
}// 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;
pragma experimental ABIEncoderV2;
import "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
interface IProxyJoinViaAggregator {
struct Quote {
address targetAggregator;
IERC20 sellToken;
IERC20 buyToken;
uint256 sellAmount;
uint256 buyAmount;
address spender;
bytes quoteCallData;
}
struct PermitToken {
IERC20 token;
bytes permitData;
}
/**
* @notice Joins the pool after trading input token(s) with the necessary ones externally to the pool
* @dev The joiningAssets and joiningAmounts should be in the same order
* @dev The request.assets and request.maxAmountIn should be in the same order as vault.getPoolTokens(poolId)
* @dev When joining the pool using the native token, the external swap should be done with the wrapped native token
* @param poolId The pool's id
* @param request The vault's join pool request
* @param fillQuotes The external trades needed before joining the pool
* @param joiningAssets The addresses of the input tokens
* @param joiningAmounts The total amounts of input tokens
* @param permitTokens The tokens that need to be permitted before joining the pool
* @param minBptAmountOut The minimum acceptable amount of pool shares received
* @param deadline Maximum deadline for accepting the joinswapExternAmountIn
* @return bptAmountOut The amount of pool shares received
*/
function permitJoinPoolViaAggregator(
bytes32 poolId,
IVault.JoinPoolRequest memory request,
Quote[] calldata fillQuotes,
IERC20[] calldata joiningAssets,
uint256[] calldata joiningAmounts,
PermitToken[] calldata permitTokens,
uint256 minBptAmountOut,
uint256 deadline
) external payable returns (uint256 bptAmountOut);
/**
* @notice Joins the pool after trading input token(s) with the necessary ones externally to the pool
* @dev The joiningAssets and joiningAmounts should be in the same order
* @dev The request.assets and request.maxAmountIn should be in the same order as vault.getPoolTokens(poolId)
* @dev When joining the pool using the native token, the external swap should be done with the wrapped native token
* @param poolId The pool's id
* @param request The vault's join pool request
* @param fillQuotes The external trades needed before joining the pool
* @param joiningAssets The addresses of the input tokens
* @param joiningAmounts The total amounts of input tokens
* @param minBptAmountOut The minimum acceptable amount of pool shares received
* @param deadline Maximum deadline for accepting the joinswapExternAmountIn
* @return bptAmountOut The amount of pool shares received
*/
function joinPoolViaAggregator(
bytes32 poolId,
IVault.JoinPoolRequest memory request,
Quote[] calldata fillQuotes,
IERC20[] calldata joiningAssets,
uint256[] calldata joiningAmounts,
uint256 minBptAmountOut,
uint256 deadline
) external payable returns (uint256 bptAmountOut);
}{
"optimizer": {
"enabled": true,
"runs": 99999
},
"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":"address","name":"_vault","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"},{"internalType":"address","name":"_zeroEx","type":"address"},{"internalType":"address","name":"_paraswap","type":"address"},{"internalType":"address","name":"_oneInch","type":"address"},{"internalType":"address","name":"_odos","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getActionId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuthorizer","outputs":[{"internalType":"contract IAuthorizer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"components":[{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"}],"internalType":"struct IVault.JoinPoolRequest","name":"request","type":"tuple"},{"components":[{"internalType":"address","name":"targetAggregator","type":"address"},{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"quoteCallData","type":"bytes"}],"internalType":"struct IProxyJoinViaAggregator.Quote[]","name":"fillQuotes","type":"tuple[]"},{"internalType":"contract IERC20[]","name":"joiningAssets","type":"address[]"},{"internalType":"uint256[]","name":"joiningAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minBptAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"joinPoolViaAggregator","outputs":[{"internalType":"uint256","name":"bptAmountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"odos","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oneInch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paraswap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"components":[{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"}],"internalType":"struct IVault.JoinPoolRequest","name":"request","type":"tuple"},{"components":[{"internalType":"address","name":"targetAggregator","type":"address"},{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"quoteCallData","type":"bytes"}],"internalType":"struct IProxyJoinViaAggregator.Quote[]","name":"fillQuotes","type":"tuple[]"},{"internalType":"contract IERC20[]","name":"joiningAssets","type":"address[]"},{"internalType":"uint256[]","name":"joiningAmounts","type":"uint256[]"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"internalType":"struct IProxyJoinViaAggregator.PermitToken[]","name":"permitTokens","type":"tuple[]"},{"internalType":"uint256","name":"minBptAmountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"permitJoinPoolViaAggregator","outputs":[{"internalType":"uint256","name":"bptAmountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zeroEx","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101806040523480156200001257600080fd5b5060405162003192380380620031928339810160408190526200003591620000b4565b6001600160601b031930606090811b82166080527fba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b00000000000000000000000060a05260016000819055805460ff1916905596871b811660c05294861b851660e05292851b84166101005290841b831661012052831b82166101405290911b166101605262000160565b60008060008060008060c08789031215620000cd578182fd5b8651620000da8162000147565b6020880151909650620000ed8162000147565b6040880151909550620001008162000147565b6060880151909450620001138162000147565b6080880151909350620001268162000147565b60a0880151909250620001398162000147565b809150509295509295509295565b6001600160a01b03811681146200015d57600080fd5b50565b60805160a05160601c60c05160601c60e05160601c6101005160601c6101205160601c6101405160601c6101605160601c612f656200022d600039806102c65280611041528061109c5250806102a25280610fbf528061101a5250806103445280610f3d5280610f985250806103205280610eb65280610f1152508061010152806102fc52806116da528061179f52806117e052806119215280611ce45250806105a852806108485280610a7f52806113f2528061150a5250806104be5250806104505250612f656000f3fe6080604052600436106100e15760003560e01c80635f6765491161007f578063893d20e811610059578063893d20e81461023c5780638c4b7aa714610251578063aaabadc514610264578063fbfa77cf146102795761012c565b80635f676549146101e75780638456cb5914610207578063851c1bb31461021c5761012c565b80633fc8cef3116100bb5780633fc8cef31461018657806352ab413b1461019b5780635af7462f146101b05780635c975abb146101c55761012c565b8063045c08d5146101315780631eba02ec1461015c5780633f4ba83a146101715761012c565b3661012c5761012a3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461020661028e565b005b600080fd5b34801561013d57600080fd5b506101466102a0565b6040516101539190612b45565b60405180910390f35b34801561016857600080fd5b506101466102c4565b34801561017d57600080fd5b5061012a6102e8565b34801561019257600080fd5b506101466102fa565b3480156101a757600080fd5b5061014661031e565b3480156101bc57600080fd5b50610146610342565b3480156101d157600080fd5b506101da610366565b6040516101539190612b8d565b6101fa6101f53660046127a8565b61036f565b6040516101539190612b98565b34801561021357600080fd5b5061012a61043a565b34801561022857600080fd5b506101fa6102373660046129a1565b61044a565b34801561024857600080fd5b506101466104bc565b6101fa61025f3660046128cc565b6104e0565b34801561027057600080fd5b50610146610597565b34801561028557600080fd5b506101466105a6565b8161029c5761029c816105ca565b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6102f06105f7565b6102f861063d565b565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015460ff1690565b6000610379610366565b156103e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6103ed61072b565b816103fc814211156021610744565b6104068686610752565b61041f8e6104138f612dfd565b8e8e8e8e8e8e8c6107ca565b91505061042a6109ad565b9c9b505050505050505050505050565b6104426105f7565b6102f86109b4565b604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527fffffffff0000000000000000000000000000000000000000000000000000000084168284015282516024818403018152604490920190925280519101205b919050565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006104ea610366565b1561055657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b61055e61072b565b8161056d814211156021610744565b61057e8c8c8c8c8c8c8c8c8c6107ca565b9150506105896109ad565b9a9950505050505050505050565b60006105a1610a7b565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b6105f4817f42414c0000000000000000000000000000000000000000000000000000000000610b1b565b50565b60006106266000357fffffffff000000000000000000000000000000000000000000000000000000001661044a565b90506105f46106358233610b96565b61019161028e565b610645610366565b6106b057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610701610ce8565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b61073d6002600054141561019061028e565b6002600055565b8161029c5761029c81610cec565b60005b818110156107c5576107bd83838381811061076c57fe5b905060200281019061077e9190612d55565b61078c9060208101906129fd565b84848481811061079857fe5b90506020028101906107aa9190612d55565b6107b8906020810190612cf2565b610d4f565b600101610755565b505050565b600061083986868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250610e2692505050565b6108438888610e7e565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f94d46688d6040518263ffffffff1660e01b815260040161089f9190612b98565b60006040518083038186803b1580156108b757600080fd5b505afa1580156108cb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261091191908101906126a1565b509150915061092a6109228d6110d4565b83838e6110da565b925061093a848410156004610744565b6109488b60400151846113b6565b610956828c602001516113bf565b610961838d8d611432565b61099e8289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061163d92505050565b50509998505050505050505050565b6001600055565b6109bc610366565b15610a2857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610701610ce8565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015610ae357600080fd5b505afa158015610af7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a191906129e1565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fd5b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b610bb56104bc565b73ffffffffffffffffffffffffffffffffffffffff1614158015610bdd5750610bdd836116b7565b15610c1f57610bea6104bc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050610ce2565b610c27610a7b565b73ffffffffffffffffffffffffffffffffffffffff16639be2a8848484306040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060206040518083038186803b158015610cb357600080fd5b505afa158015610cc7573d6000803e3d6000fd5b505050506040513d6020811015610cdd57600080fd5b505190505b92915050565b3390565b6030600a820601600a820491506030600a8306018060081b82016753574141502300000160c01b9150507f08c379a00000000000000000000000000000000000000000000000000000000060005260206004526008602452806044525060646000fd5b610d5d60e082146023610744565b6000808473ffffffffffffffffffffffffffffffffffffffff1663d505accf60e01b8585604051602001610d9393929190612aed565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610dcb91612b29565b6000604051808303816000865af19150503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b509150915081610e1f57805160208201fd5b5050505050565b81518151610e359082906116bd565b60005b81811015610e7857610e70848281518110610e4f57fe5b6020026020010151848381518110610e6357fe5b60200260200101516116ca565b600101610e38565b50505050565b60005b818110156107c5576000838383818110610e9757fe5b9050602002810190610ea99190612d88565b610eb290612e09565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415610f3b57610f367f000000000000000000000000000000000000000000000000000000000000000082611780565b6110cb565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415610fbd57610f367f000000000000000000000000000000000000000000000000000000000000000082611780565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16141561103f57610f367f000000000000000000000000000000000000000000000000000000000000000082611780565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff1614156110c157610f367f000000000000000000000000000000000000000000000000000000000000000082611780565b6110cb6020610cec565b50600101610e81565b60601c90565b600080835190506110f0818460200151516116bd565b6000855167ffffffffffffffff8111801561110a57600080fd5b50604051908082528060200260200182016040528015611134578160200160208202803683370190505b50905060005b8281101561117d5761115e87828151811061115157fe5b60200260200101516118d4565b82828151811061116a57fe5b602090810291909101015260010161113a565b5060008773ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b1580156111c657600080fd5b505afa1580156111da573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611220919081019061276d565b905061122c82826119ff565b61123686826119ff565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005b838110156112ac57600061129584838151811061127457fe5b602002602001015189848151811061128857fe5b6020026020010151611a68565b9050828110156112a3578092505b5060010161125b565b506000611336828a73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112f957600080fd5b505afa15801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190612a19565b611abb565b905060006113478760400151611aee565b905060006113558383611b0b565b905060005b868110156113a6576113838960200151828151811061137557fe5b602002602001015183611b58565b8960200151828151811061139357fe5b602090810291909101015260010161135a565b50919a9950505050505050505050565b60409190910152565b815181516113ce9082906116bd565b60005b81811015610e785761142a8482815181106113e857fe5b60200260200101517f000000000000000000000000000000000000000000000000000000000000000085848151811061141d57fe5b6020026020010151611b90565b6001016113d1565b600061143d836110d4565b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161147a9190612b45565b60206040518083038186803b15801561149257600080fd5b505afa1580156114a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ca9190612a19565b6040517fb95cac2800000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b95cac2890611545908790309033908990600401612ba1565b600060405180830381600087803b15801561155f57600080fd5b505af1158015611573573d6000803e3d6000fd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081526000925073ffffffffffffffffffffffffffffffffffffffff851691506370a08231906115cc903390600401612b45565b60206040518083038186803b1580156115e457600080fd5b505afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190612a19565b90506116358661162c8385611c7d565b10156004610744565b505050505050565b60005b815181101561167c57600082828151811061165757fe5b602002602001015190506116738161166e836118d4565b611c93565b50600101611640565b5060005b82518110156107c557600083828151811061169757fe5b602002602001015190506116ae8161166e836118d4565b50600101611680565b50600090565b61029c818314606761028e565b6116d382611d7e565b1561175e577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561174057600080fd5b505af1158015611754573d6000803e3d6000fd5b505050505061029c565b61029c73ffffffffffffffffffffffffffffffffffffffff8316333084611d98565b600061178f8260200151611d7e565b61179d5781602001516117bf565b7f00000000000000000000000000000000000000000000000000000000000000005b905060006117d08360400151611d7e565b6117de578260400151611800565b7f00000000000000000000000000000000000000000000000000000000000000005b9050600061180d836118d4565b9050600061181a836118d4565b90506118568473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156022610744565b611869848660a001518760600151611b90565b611877868660c00151611e2d565b50600061188d611886866118d4565b8490611c7d565b905060006118a48361189e876118d4565b90611c7d565b90506118b887606001518311156000610744565b6118ca87608001518210156004610744565b5050505050505050565b60006118df82611d7e565b156119ad576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906370a0823190611956903090600401612b45565b60206040518083038186803b15801561196e57600080fd5b505afa158015611982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a69190612a19565b90506104b7565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190611956903090600401612b45565b81518151611a0e9082906116bd565b60005b81811015610e7857611a49848281518110611a2857fe5b6020026020010151848381518110611a3c57fe5b6020026020010151611abb565b848281518110611a5557fe5b6020908102919091010152600101611a11565b6000611a77821515600461028e565b670de0b6b3a76400008302611aa9841580611aa25750670de0b6b3a7640000858381611a9f57fe5b04145b600561028e565b828181611ab257fe5b04949350505050565b6000828202611adf841580611ad8575083858381611ad557fe5b04145b600361028e565b670de0b6b3a764000081611ab2565b600081806020019051810190611b049190612a31565b9392505050565b6000611b1a821515600461028e565b670de0b6b3a76400008302611b42841580611aa25750670de0b6b3a7640000858381611a9f57fe5b6001836001830304018115150291505092915050565b6000828202611b72841580611ad8575083858381611ad557fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152819073ffffffffffffffffffffffffffffffffffffffff85169063dd62ed3e90611be69030908790600401612b66565b60206040518083038186803b158015611bfe57600080fd5b505afa158015611c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c369190612a19565b10156107c5576107c573ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611f3f565b6000611c8d83831115600161028e565b50900390565b801561029c57611ca282611d7e565b15611d5d576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90611d19908490600401612b98565b600060405180830381600087803b158015611d3357600080fd5b505af1158015611d47573d6000803e3d6000fd5b50611d589250339150839050612110565b61029c565b61029c73ffffffffffffffffffffffffffffffffffffffff83163383612236565b73ffffffffffffffffffffffffffffffffffffffff161590565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610e789085906122bf565b60208101516060907fffffffff0000000000000000000000000000000000000000000000000000000081167f23b872dd000000000000000000000000000000000000000000000000000000001415611eba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eb190612c95565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff1685604051611ee29190612b29565b6000604051808303816000865af19150503d8060008114611f1f576040519150601f19603f3d011682016040523d82523d6000602084013e611f24565b606091505b509150915081611f3657805160208601fd5b95945050505050565b8015801590611fee5750604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611fbf57600080fd5b505afa158015611fd3573d6000803e3d6000fd5b505050506040513d6020811015611fe957600080fd5b505115155b15612083576040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260006044808301919091528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526120839084906122bf565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526107c59084906122bf565b8047101561217f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b60405160009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d80600081146121d7576040519150601f19603f3d011682016040523d82523d6000602084013e6121dc565b606091505b50509050806107c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a815260200180612ef6603a913960400191505060405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526107c59084905b6000808373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061232757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016122ea565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612389576040519150601f19603f3d011682016040523d82523d6000602084013e61238e565b606091505b509150915060008214156123a6573d6000803e3d6000fd5b610e788151600014806123cc57508180602001905160208110156123c957600080fd5b50515b6101a261028e565b80356104b781612ed3565b600082601f8301126123ef578081fd5b813560206124046123ff83612ddf565b612dbb565b8281528181019085830183850287018401881015612420578586fd5b855b8581101561244757813561243581612ed3565b84529284019290840190600101612422565b5090979650505050505050565b60008083601f840112612465578182fd5b50813567ffffffffffffffff81111561247c578182fd5b602083019150836020808302850101111561249657600080fd5b9250929050565b600082601f8301126124ad578081fd5b813560206124bd6123ff83612ddf565b82815281810190858301838502870184018810156124d9578586fd5b855b85811015612447578135845292840192908401906001016124db565b600082601f830112612507578081fd5b815160206125176123ff83612ddf565b8281528181019085830183850287018401881015612533578586fd5b855b8581101561244757815184529284019290840190600101612535565b803580151581146104b757600080fd5b600082601f830112612571578081fd5b813567ffffffffffffffff81111561258557fe5b6125b660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612dbb565b8181528460208386010111156125ca578283fd5b816020850160208301379081016020019190915292915050565b6000608082840312156125f5578081fd5b50919050565b60006080828403121561260c578081fd5b6126166080612dbb565b9050813567ffffffffffffffff8082111561263057600080fd5b61263c858386016123df565b8352602084013591508082111561265257600080fd5b61265e8583860161249d565b6020840152604084013591508082111561267757600080fd5b5061268484828501612561565b60408301525061269660608301612551565b606082015292915050565b6000806000606084860312156126b5578283fd5b835167ffffffffffffffff808211156126cc578485fd5b818601915086601f8301126126df578485fd5b815160206126ef6123ff83612ddf565b82815281810190858301838502870184018c101561270b57898afd5b8996505b8487101561273657805161272281612ed3565b83526001969096019591830191830161270f565b509189015191975090935050508082111561274f578384fd5b5061275c868287016124f7565b925050604084015190509250925092565b60006020828403121561277e578081fd5b815167ffffffffffffffff811115612794578182fd5b6127a0848285016124f7565b949350505050565b6000806000806000806000806000806000806101008d8f0312156127ca57898afd5b8c359b5067ffffffffffffffff60208e013511156127e657898afd5b6127f68e60208f01358f016125e4565b9a5067ffffffffffffffff60408e0135111561281057898afd5b6128208e60408f01358f01612454565b909a50985067ffffffffffffffff60608e0135111561283d578788fd5b61284d8e60608f01358f01612454565b909850965067ffffffffffffffff60808e0135111561286a578586fd5b61287a8e60808f01358f01612454565b909650945067ffffffffffffffff60a08e01351115612897578384fd5b6128a78e60a08f01358f01612454565b9c9f9b9e50999c989b979a969995989497959660c08601359560e00135945092505050565b60008060008060008060008060008060e08b8d0312156128ea578384fd5b8a35995060208b013567ffffffffffffffff80821115612908578586fd5b6129148e838f016125fb565b9a5060408d0135915080821115612929578586fd5b6129358e838f01612454565b909a50985060608d013591508082111561294d578586fd5b6129598e838f01612454565b909850965060808d0135915080821115612971578586fd5b5061297e8d828e01612454565b9b9e9a9d50989b979a969995989760a08101359660c09091013595509350505050565b6000602082840312156129b2578081fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b04578182fd5b6000602082840312156129f2578081fd5b8151611b0481612ed3565b600060208284031215612a0e578081fd5b8135611b0481612ed3565b600060208284031215612a2a578081fd5b5051919050565b60008060408385031215612a43578182fd5b825160ff81168114612a53578283fd5b6020939093015192949293505050565b6000815180845260208085019450808401835b83811015612a9257815187529582019590820190600101612a76565b509495945050505050565b15159052565b60008151808452612abb816020860160208601612ea7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60007fffffffff000000000000000000000000000000000000000000000000000000008516825282846004840137910160040190815292915050565b60008251612b3b818460208701612ea7565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b901515815260200190565b90815260200190565b6000858252602073ffffffffffffffffffffffffffffffffffffffff80871682850152808616604085015260806060850152610100840185516080808701528181518084526101208801915085830193508692505b80831015612c1857835185168252928501926001929092019190850190612bf6565b508488015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809350838782030160a0880152612c568186612a63565b94505050506040850151818584030160c0860152612c748382612aa3565b925050506060840151612c8a60e0850182612a9d565b509695505050505050565b60208082526029908201527f7472616e7366657246726f6d206e6f7420616c6c6f77656420666f722065787460408201527f65726e616c43616c6c0000000000000000000000000000000000000000000000606082015260800190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d26578283fd5b83018035915067ffffffffffffffff821115612d40578283fd5b60200191503681900382131561249657600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612b3b578182fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612b3b578182fd5b60405181810167ffffffffffffffff81118282101715612dd757fe5b604052919050565b600067ffffffffffffffff821115612df357fe5b5060209081020190565b6000610ce236836125fb565b600060e08236031215612e1a578081fd5b612e2460e0612dbb565b612e2d836123d4565b8152612e3b602084016123d4565b6020820152612e4c604084016123d4565b60408201526060830135606082015260808301356080820152612e7160a084016123d4565b60a082015260c083013567ffffffffffffffff811115612e8f578283fd5b612e9b36828601612561565b60c08301525092915050565b60005b83811015612ec2578181015183820152602001612eaa565b83811115610e785750506000910152565b73ffffffffffffffffffffffffffffffffffffffff811681146105f457600080fdfe416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564a26469706673582212200f36a712a790acbe276c81840d8f372beae3241afb32694746157236add7353f64736f6c63430007060033000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629300000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee570000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e13
Deployed Bytecode
0x6080604052600436106100e15760003560e01c80635f6765491161007f578063893d20e811610059578063893d20e81461023c5780638c4b7aa714610251578063aaabadc514610264578063fbfa77cf146102795761012c565b80635f676549146101e75780638456cb5914610207578063851c1bb31461021c5761012c565b80633fc8cef3116100bb5780633fc8cef31461018657806352ab413b1461019b5780635af7462f146101b05780635c975abb146101c55761012c565b8063045c08d5146101315780631eba02ec1461015c5780633f4ba83a146101715761012c565b3661012c5761012a3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1161461020661028e565b005b600080fd5b34801561013d57600080fd5b506101466102a0565b6040516101539190612b45565b60405180910390f35b34801561016857600080fd5b506101466102c4565b34801561017d57600080fd5b5061012a6102e8565b34801561019257600080fd5b506101466102fa565b3480156101a757600080fd5b5061014661031e565b3480156101bc57600080fd5b50610146610342565b3480156101d157600080fd5b506101da610366565b6040516101539190612b8d565b6101fa6101f53660046127a8565b61036f565b6040516101539190612b98565b34801561021357600080fd5b5061012a61043a565b34801561022857600080fd5b506101fa6102373660046129a1565b61044a565b34801561024857600080fd5b506101466104bc565b6101fa61025f3660046128cc565b6104e0565b34801561027057600080fd5b50610146610597565b34801561028557600080fd5b506101466105a6565b8161029c5761029c816105ca565b5050565b7f0000000000000000000000001111111254eeb25477b68fb85ed929f73a96058281565b7f000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e1381565b6102f06105f7565b6102f861063d565b565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab181565b7f000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff81565b7f000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee5781565b60015460ff1690565b6000610379610366565b156103e557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6103ed61072b565b816103fc814211156021610744565b6104068686610752565b61041f8e6104138f612dfd565b8e8e8e8e8e8e8c6107ca565b91505061042a6109ad565b9c9b505050505050505050505050565b6104426105f7565b6102f86109b4565b604080517f53675f3072b97ef652651d863b1cef5203438ad30000000000000000000000006020808301919091527fffffffff0000000000000000000000000000000000000000000000000000000084168284015282516024818403018152604490920190925280519101205b919050565b7f000000000000000000000000ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b90565b60006104ea610366565b1561055657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b61055e61072b565b8161056d814211156021610744565b61057e8c8c8c8c8c8c8c8c8c6107ca565b9150506105896109ad565b9a9950505050505050505050565b60006105a1610a7b565b905090565b7f000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629381565b6105f4817f42414c0000000000000000000000000000000000000000000000000000000000610b1b565b50565b60006106266000357fffffffff000000000000000000000000000000000000000000000000000000001661044a565b90506105f46106358233610b96565b61019161028e565b610645610366565b6106b057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610701610ce8565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b61073d6002600054141561019061028e565b6002600055565b8161029c5761029c81610cec565b60005b818110156107c5576107bd83838381811061076c57fe5b905060200281019061077e9190612d55565b61078c9060208101906129fd565b84848481811061079857fe5b90506020028101906107aa9190612d55565b6107b8906020810190612cf2565b610d4f565b600101610755565b505050565b600061083986868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250610e2692505050565b6108438888610e7e565b6000807f000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629373ffffffffffffffffffffffffffffffffffffffff1663f94d46688d6040518263ffffffff1660e01b815260040161089f9190612b98565b60006040518083038186803b1580156108b757600080fd5b505afa1580156108cb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261091191908101906126a1565b509150915061092a6109228d6110d4565b83838e6110da565b925061093a848410156004610744565b6109488b60400151846113b6565b610956828c602001516113bf565b610961838d8d611432565b61099e8289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061163d92505050565b50509998505050505050505050565b6001600055565b6109bc610366565b15610a2857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610701610ce8565b60007f000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629373ffffffffffffffffffffffffffffffffffffffff1663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015610ae357600080fd5b505afa158015610af7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a191906129e1565b7f08c379a000000000000000000000000000000000000000000000000000000000600090815260206004526007602452600a808404818106603090810160081b958390069590950190829004918206850160101b01602363ffffff0060e086901c160160181b0190930160c81b60445260e882901c90606490fd5b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b610bb56104bc565b73ffffffffffffffffffffffffffffffffffffffff1614158015610bdd5750610bdd836116b7565b15610c1f57610bea6104bc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050610ce2565b610c27610a7b565b73ffffffffffffffffffffffffffffffffffffffff16639be2a8848484306040518463ffffffff1660e01b8152600401808481526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060206040518083038186803b158015610cb357600080fd5b505afa158015610cc7573d6000803e3d6000fd5b505050506040513d6020811015610cdd57600080fd5b505190505b92915050565b3390565b6030600a820601600a820491506030600a8306018060081b82016753574141502300000160c01b9150507f08c379a00000000000000000000000000000000000000000000000000000000060005260206004526008602452806044525060646000fd5b610d5d60e082146023610744565b6000808473ffffffffffffffffffffffffffffffffffffffff1663d505accf60e01b8585604051602001610d9393929190612aed565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610dcb91612b29565b6000604051808303816000865af19150503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b509150915081610e1f57805160208201fd5b5050505050565b81518151610e359082906116bd565b60005b81811015610e7857610e70848281518110610e4f57fe5b6020026020010151848381518110610e6357fe5b60200260200101516116ca565b600101610e38565b50505050565b60005b818110156107c5576000838383818110610e9757fe5b9050602002810190610ea99190612d88565b610eb290612e09565b90507f000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415610f3b57610f367f000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff82611780565b6110cb565b7f000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee5773ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161415610fbd57610f367f000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee5782611780565b7f0000000000000000000000001111111254eeb25477b68fb85ed929f73a96058273ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff16141561103f57610f367f0000000000000000000000001111111254eeb25477b68fb85ed929f73a96058282611780565b7f000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e1373ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff1614156110c157610f367f000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e1382611780565b6110cb6020610cec565b50600101610e81565b60601c90565b600080835190506110f0818460200151516116bd565b6000855167ffffffffffffffff8111801561110a57600080fd5b50604051908082528060200260200182016040528015611134578160200160208202803683370190505b50905060005b8281101561117d5761115e87828151811061115157fe5b60200260200101516118d4565b82828151811061116a57fe5b602090810291909101015260010161113a565b5060008773ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b1580156111c657600080fd5b505afa1580156111da573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611220919081019061276d565b905061122c82826119ff565b61123686826119ff565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005b838110156112ac57600061129584838151811061127457fe5b602002602001015189848151811061128857fe5b6020026020010151611a68565b9050828110156112a3578092505b5060010161125b565b506000611336828a73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112f957600080fd5b505afa15801561130d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113319190612a19565b611abb565b905060006113478760400151611aee565b905060006113558383611b0b565b905060005b868110156113a6576113838960200151828151811061137557fe5b602002602001015183611b58565b8960200151828151811061139357fe5b602090810291909101015260010161135a565b50919a9950505050505050505050565b60409190910152565b815181516113ce9082906116bd565b60005b81811015610e785761142a8482815181106113e857fe5b60200260200101517f000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629385848151811061141d57fe5b6020026020010151611b90565b6001016113d1565b600061143d836110d4565b905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b815260040161147a9190612b45565b60206040518083038186803b15801561149257600080fd5b505afa1580156114a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ca9190612a19565b6040517fb95cac2800000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d315a9c38ec871068fec378e4ce78af528c76293169063b95cac2890611545908790309033908990600401612ba1565b600060405180830381600087803b15801561155f57600080fd5b505af1158015611573573d6000803e3d6000fd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081526000925073ffffffffffffffffffffffffffffffffffffffff851691506370a08231906115cc903390600401612b45565b60206040518083038186803b1580156115e457600080fd5b505afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190612a19565b90506116358661162c8385611c7d565b10156004610744565b505050505050565b60005b815181101561167c57600082828151811061165757fe5b602002602001015190506116738161166e836118d4565b611c93565b50600101611640565b5060005b82518110156107c557600083828151811061169757fe5b602002602001015190506116ae8161166e836118d4565b50600101611680565b50600090565b61029c818314606761028e565b6116d382611d7e565b1561175e577f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561174057600080fd5b505af1158015611754573d6000803e3d6000fd5b505050505061029c565b61029c73ffffffffffffffffffffffffffffffffffffffff8316333084611d98565b600061178f8260200151611d7e565b61179d5781602001516117bf565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab15b905060006117d08360400151611d7e565b6117de578260400151611800565b7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab15b9050600061180d836118d4565b9050600061181a836118d4565b90506118568473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156022610744565b611869848660a001518760600151611b90565b611877868660c00151611e2d565b50600061188d611886866118d4565b8490611c7d565b905060006118a48361189e876118d4565b90611c7d565b90506118b887606001518311156000610744565b6118ca87608001518210156004610744565b5050505050505050565b60006118df82611d7e565b156119ad576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab116906370a0823190611956903090600401612b45565b60206040518083038186803b15801561196e57600080fd5b505afa158015611982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a69190612a19565b90506104b7565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906370a0823190611956903090600401612b45565b81518151611a0e9082906116bd565b60005b81811015610e7857611a49848281518110611a2857fe5b6020026020010151848381518110611a3c57fe5b6020026020010151611abb565b848281518110611a5557fe5b6020908102919091010152600101611a11565b6000611a77821515600461028e565b670de0b6b3a76400008302611aa9841580611aa25750670de0b6b3a7640000858381611a9f57fe5b04145b600561028e565b828181611ab257fe5b04949350505050565b6000828202611adf841580611ad8575083858381611ad557fe5b04145b600361028e565b670de0b6b3a764000081611ab2565b600081806020019051810190611b049190612a31565b9392505050565b6000611b1a821515600461028e565b670de0b6b3a76400008302611b42841580611aa25750670de0b6b3a7640000858381611a9f57fe5b6001836001830304018115150291505092915050565b6000828202611b72841580611ad8575083858381611ad557fe5b6001670de0b6b3a76400006001830304018115150291505092915050565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152819073ffffffffffffffffffffffffffffffffffffffff85169063dd62ed3e90611be69030908790600401612b66565b60206040518083038186803b158015611bfe57600080fd5b505afa158015611c12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c369190612a19565b10156107c5576107c573ffffffffffffffffffffffffffffffffffffffff8416837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611f3f565b6000611c8d83831115600161028e565b50900390565b801561029c57611ca282611d7e565b15611d5d576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab11690632e1a7d4d90611d19908490600401612b98565b600060405180830381600087803b158015611d3357600080fd5b505af1158015611d47573d6000803e3d6000fd5b50611d589250339150839050612110565b61029c565b61029c73ffffffffffffffffffffffffffffffffffffffff83163383612236565b73ffffffffffffffffffffffffffffffffffffffff161590565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610e789085906122bf565b60208101516060907fffffffff0000000000000000000000000000000000000000000000000000000081167f23b872dd000000000000000000000000000000000000000000000000000000001415611eba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eb190612c95565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff1685604051611ee29190612b29565b6000604051808303816000865af19150503d8060008114611f1f576040519150601f19603f3d011682016040523d82523d6000602084013e611f24565b606091505b509150915081611f3657805160208601fd5b95945050505050565b8015801590611fee5750604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611fbf57600080fd5b505afa158015611fd3573d6000803e3d6000fd5b505050506040513d6020811015611fe957600080fd5b505115155b15612083576040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260006044808301919091528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526120839084906122bf565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526107c59084906122bf565b8047101561217f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015290519081900360640190fd5b60405160009073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d80600081146121d7576040519150601f19603f3d011682016040523d82523d6000602084013e6121dc565b606091505b50509050806107c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a815260200180612ef6603a913960400191505060405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526107c59084905b6000808373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061232757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016122ea565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612389576040519150601f19603f3d011682016040523d82523d6000602084013e61238e565b606091505b509150915060008214156123a6573d6000803e3d6000fd5b610e788151600014806123cc57508180602001905160208110156123c957600080fd5b50515b6101a261028e565b80356104b781612ed3565b600082601f8301126123ef578081fd5b813560206124046123ff83612ddf565b612dbb565b8281528181019085830183850287018401881015612420578586fd5b855b8581101561244757813561243581612ed3565b84529284019290840190600101612422565b5090979650505050505050565b60008083601f840112612465578182fd5b50813567ffffffffffffffff81111561247c578182fd5b602083019150836020808302850101111561249657600080fd5b9250929050565b600082601f8301126124ad578081fd5b813560206124bd6123ff83612ddf565b82815281810190858301838502870184018810156124d9578586fd5b855b85811015612447578135845292840192908401906001016124db565b600082601f830112612507578081fd5b815160206125176123ff83612ddf565b8281528181019085830183850287018401881015612533578586fd5b855b8581101561244757815184529284019290840190600101612535565b803580151581146104b757600080fd5b600082601f830112612571578081fd5b813567ffffffffffffffff81111561258557fe5b6125b660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612dbb565b8181528460208386010111156125ca578283fd5b816020850160208301379081016020019190915292915050565b6000608082840312156125f5578081fd5b50919050565b60006080828403121561260c578081fd5b6126166080612dbb565b9050813567ffffffffffffffff8082111561263057600080fd5b61263c858386016123df565b8352602084013591508082111561265257600080fd5b61265e8583860161249d565b6020840152604084013591508082111561267757600080fd5b5061268484828501612561565b60408301525061269660608301612551565b606082015292915050565b6000806000606084860312156126b5578283fd5b835167ffffffffffffffff808211156126cc578485fd5b818601915086601f8301126126df578485fd5b815160206126ef6123ff83612ddf565b82815281810190858301838502870184018c101561270b57898afd5b8996505b8487101561273657805161272281612ed3565b83526001969096019591830191830161270f565b509189015191975090935050508082111561274f578384fd5b5061275c868287016124f7565b925050604084015190509250925092565b60006020828403121561277e578081fd5b815167ffffffffffffffff811115612794578182fd5b6127a0848285016124f7565b949350505050565b6000806000806000806000806000806000806101008d8f0312156127ca57898afd5b8c359b5067ffffffffffffffff60208e013511156127e657898afd5b6127f68e60208f01358f016125e4565b9a5067ffffffffffffffff60408e0135111561281057898afd5b6128208e60408f01358f01612454565b909a50985067ffffffffffffffff60608e0135111561283d578788fd5b61284d8e60608f01358f01612454565b909850965067ffffffffffffffff60808e0135111561286a578586fd5b61287a8e60808f01358f01612454565b909650945067ffffffffffffffff60a08e01351115612897578384fd5b6128a78e60a08f01358f01612454565b9c9f9b9e50999c989b979a969995989497959660c08601359560e00135945092505050565b60008060008060008060008060008060e08b8d0312156128ea578384fd5b8a35995060208b013567ffffffffffffffff80821115612908578586fd5b6129148e838f016125fb565b9a5060408d0135915080821115612929578586fd5b6129358e838f01612454565b909a50985060608d013591508082111561294d578586fd5b6129598e838f01612454565b909850965060808d0135915080821115612971578586fd5b5061297e8d828e01612454565b9b9e9a9d50989b979a969995989760a08101359660c09091013595509350505050565b6000602082840312156129b2578081fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b04578182fd5b6000602082840312156129f2578081fd5b8151611b0481612ed3565b600060208284031215612a0e578081fd5b8135611b0481612ed3565b600060208284031215612a2a578081fd5b5051919050565b60008060408385031215612a43578182fd5b825160ff81168114612a53578283fd5b6020939093015192949293505050565b6000815180845260208085019450808401835b83811015612a9257815187529582019590820190600101612a76565b509495945050505050565b15159052565b60008151808452612abb816020860160208601612ea7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60007fffffffff000000000000000000000000000000000000000000000000000000008516825282846004840137910160040190815292915050565b60008251612b3b818460208701612ea7565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b901515815260200190565b90815260200190565b6000858252602073ffffffffffffffffffffffffffffffffffffffff80871682850152808616604085015260806060850152610100840185516080808701528181518084526101208801915085830193508692505b80831015612c1857835185168252928501926001929092019190850190612bf6565b508488015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff809350838782030160a0880152612c568186612a63565b94505050506040850151818584030160c0860152612c748382612aa3565b925050506060840151612c8a60e0850182612a9d565b509695505050505050565b60208082526029908201527f7472616e7366657246726f6d206e6f7420616c6c6f77656420666f722065787460408201527f65726e616c43616c6c0000000000000000000000000000000000000000000000606082015260800190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d26578283fd5b83018035915067ffffffffffffffff821115612d40578283fd5b60200191503681900382131561249657600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112612b3b578182fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff21833603018112612b3b578182fd5b60405181810167ffffffffffffffff81118282101715612dd757fe5b604052919050565b600067ffffffffffffffff821115612df357fe5b5060209081020190565b6000610ce236836125fb565b600060e08236031215612e1a578081fd5b612e2460e0612dbb565b612e2d836123d4565b8152612e3b602084016123d4565b6020820152612e4c604084016123d4565b60408201526060830135606082015260808301356080820152612e7160a084016123d4565b60a082015260c083013567ffffffffffffffff811115612e8f578283fd5b612e9b36828601612561565b60c08301525092915050565b60005b83811015612ec2578181015183820152602001612eaa565b83811115610e785750506000910152565b73ffffffffffffffffffffffffffffffffffffffff811681146105f457600080fdfe416464726573733a20756e61626c6520746f2073656e642076616c75652c20726563697069656e74206d61792068617665207265766572746564a26469706673582212200f36a712a790acbe276c81840d8f372beae3241afb32694746157236add7353f64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d315a9c38ec871068fec378e4ce78af528c7629300000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee570000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e13
-----Decoded View---------------
Arg [0] : _vault (address): 0xd315a9C38eC871068FEC378E4Ce78AF528C76293
Arg [1] : _weth (address): 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
Arg [2] : _zeroEx (address): 0xDef1C0ded9bec7F1a1670819833240f027b25EfF
Arg [3] : _paraswap (address): 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57
Arg [4] : _oneInch (address): 0x1111111254EEB25477B68fb85Ed929f73A960582
Arg [5] : _odos (address): 0xa669e7A0d4b3e4Fa48af2dE86BD4CD7126Be4e13
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000d315a9c38ec871068fec378e4ce78af528c76293
Arg [1] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [2] : 000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff
Arg [3] : 000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57
Arg [4] : 0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582
Arg [5] : 000000000000000000000000a669e7a0d4b3e4fa48af2de86bd4cd7126be4e13
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.