Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
13601983 | 1137 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
WeightedPool
Compiler Version
v0.7.1+commit.f4a555be
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; import "../../lib/math/FixedPoint.sol"; import "../../lib/helpers/InputHelpers.sol"; import "../BaseMinimalSwapInfoPool.sol"; import "./WeightedMath.sol"; import "./WeightedPoolUserDataHelpers.sol"; // This contract relies on tons of immutable state variables to perform efficient lookup, without resorting to storage // reads. Because immutable arrays are not supported, we instead declare a fixed set of state variables plus total // count, resulting in a large number of state variables. contract WeightedPool is BaseMinimalSwapInfoPool, WeightedMath { using FixedPoint for uint256; using WeightedPoolUserDataHelpers for bytes; // The protocol fees will always be charged using the token associated with the max weight in the pool. // Since these Pools will register tokens only once, we can assume this index will be constant. uint256 private immutable _maxWeightTokenIndex; uint256 private immutable _normalizedWeight0; uint256 private immutable _normalizedWeight1; uint256 private immutable _normalizedWeight2; uint256 private immutable _normalizedWeight3; uint256 private immutable _normalizedWeight4; uint256 private immutable _normalizedWeight5; uint256 private immutable _normalizedWeight6; uint256 private immutable _normalizedWeight7; uint256 private _lastInvariant; enum JoinKind { INIT, EXACT_TOKENS_IN_FOR_BPT_OUT, TOKEN_IN_FOR_EXACT_BPT_OUT } enum ExitKind { EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, EXACT_BPT_IN_FOR_TOKENS_OUT, BPT_IN_FOR_EXACT_TOKENS_OUT } constructor( IVault vault, string memory name, string memory symbol, IERC20[] memory tokens, uint256[] memory normalizedWeights, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner ) BaseMinimalSwapInfoPool( vault, name, symbol, tokens, swapFeePercentage, pauseWindowDuration, bufferPeriodDuration, owner ) { uint256 numTokens = tokens.length; InputHelpers.ensureInputLengthMatch(numTokens, normalizedWeights.length); // Ensure each normalized weight is above them minimum and find the token index of the maximum weight uint256 normalizedSum = 0; uint256 maxWeightTokenIndex = 0; uint256 maxNormalizedWeight = 0; for (uint8 i = 0; i < numTokens; i++) { uint256 normalizedWeight = normalizedWeights[i]; _require(normalizedWeight >= _MIN_WEIGHT, Errors.MIN_WEIGHT); normalizedSum = normalizedSum.add(normalizedWeight); if (normalizedWeight > maxNormalizedWeight) { maxWeightTokenIndex = i; maxNormalizedWeight = normalizedWeight; } } // Ensure that the normalized weights sum to ONE _require(normalizedSum == FixedPoint.ONE, Errors.NORMALIZED_WEIGHT_INVARIANT); _maxWeightTokenIndex = maxWeightTokenIndex; _normalizedWeight0 = normalizedWeights.length > 0 ? normalizedWeights[0] : 0; _normalizedWeight1 = normalizedWeights.length > 1 ? normalizedWeights[1] : 0; _normalizedWeight2 = normalizedWeights.length > 2 ? normalizedWeights[2] : 0; _normalizedWeight3 = normalizedWeights.length > 3 ? normalizedWeights[3] : 0; _normalizedWeight4 = normalizedWeights.length > 4 ? normalizedWeights[4] : 0; _normalizedWeight5 = normalizedWeights.length > 5 ? normalizedWeights[5] : 0; _normalizedWeight6 = normalizedWeights.length > 6 ? normalizedWeights[6] : 0; _normalizedWeight7 = normalizedWeights.length > 7 ? normalizedWeights[7] : 0; } function _normalizedWeight(IERC20 token) internal view virtual returns (uint256) { // prettier-ignore if (token == _token0) { return _normalizedWeight0; } else if (token == _token1) { return _normalizedWeight1; } else if (token == _token2) { return _normalizedWeight2; } else if (token == _token3) { return _normalizedWeight3; } else if (token == _token4) { return _normalizedWeight4; } else if (token == _token5) { return _normalizedWeight5; } else if (token == _token6) { return _normalizedWeight6; } else if (token == _token7) { return _normalizedWeight7; } else { _revert(Errors.INVALID_TOKEN); } } function _normalizedWeights() internal view virtual returns (uint256[] memory) { uint256 totalTokens = _getTotalTokens(); uint256[] memory normalizedWeights = new uint256[](totalTokens); // prettier-ignore { if (totalTokens > 0) { normalizedWeights[0] = _normalizedWeight0; } else { return normalizedWeights; } if (totalTokens > 1) { normalizedWeights[1] = _normalizedWeight1; } else { return normalizedWeights; } if (totalTokens > 2) { normalizedWeights[2] = _normalizedWeight2; } else { return normalizedWeights; } if (totalTokens > 3) { normalizedWeights[3] = _normalizedWeight3; } else { return normalizedWeights; } if (totalTokens > 4) { normalizedWeights[4] = _normalizedWeight4; } else { return normalizedWeights; } if (totalTokens > 5) { normalizedWeights[5] = _normalizedWeight5; } else { return normalizedWeights; } if (totalTokens > 6) { normalizedWeights[6] = _normalizedWeight6; } else { return normalizedWeights; } if (totalTokens > 7) { normalizedWeights[7] = _normalizedWeight7; } else { return normalizedWeights; } } return normalizedWeights; } function getLastInvariant() external view returns (uint256) { return _lastInvariant; } /** * @dev Returns the current value of the invariant. */ function getInvariant() public view returns (uint256) { (, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId()); // Since the Pool hooks always work with upscaled balances, we manually // upscale here for consistency _upscaleArray(balances, _scalingFactors()); uint256[] memory normalizedWeights = _normalizedWeights(); return WeightedMath._calculateInvariant(normalizedWeights, balances); } function getNormalizedWeights() external view returns (uint256[] memory) { return _normalizedWeights(); } // Base Pool handlers // Swap function _onSwapGivenIn( SwapRequest memory swapRequest, uint256 currentBalanceTokenIn, uint256 currentBalanceTokenOut ) internal view virtual override whenNotPaused returns (uint256) { // Swaps are disabled while the contract is paused. return WeightedMath._calcOutGivenIn( currentBalanceTokenIn, _normalizedWeight(swapRequest.tokenIn), currentBalanceTokenOut, _normalizedWeight(swapRequest.tokenOut), swapRequest.amount ); } function _onSwapGivenOut( SwapRequest memory swapRequest, uint256 currentBalanceTokenIn, uint256 currentBalanceTokenOut ) internal view virtual override whenNotPaused returns (uint256) { // Swaps are disabled while the contract is paused. return WeightedMath._calcInGivenOut( currentBalanceTokenIn, _normalizedWeight(swapRequest.tokenIn), currentBalanceTokenOut, _normalizedWeight(swapRequest.tokenOut), swapRequest.amount ); } // Initialize function _onInitializePool( bytes32, address, address, bytes memory userData ) internal virtual override whenNotPaused returns (uint256, uint256[] memory) { // It would be strange for the Pool to be paused before it is initialized, but for consistency we prevent // initialization in this case. WeightedPool.JoinKind kind = userData.joinKind(); _require(kind == WeightedPool.JoinKind.INIT, Errors.UNINITIALIZED); uint256[] memory amountsIn = userData.initialAmountsIn(); InputHelpers.ensureInputLengthMatch(_getTotalTokens(), amountsIn.length); _upscaleArray(amountsIn, _scalingFactors()); uint256[] memory normalizedWeights = _normalizedWeights(); uint256 invariantAfterJoin = WeightedMath._calculateInvariant(normalizedWeights, amountsIn); // Set the initial BPT to the value of the invariant times the number of tokens. This makes BPT supply more // consistent in Pools with similar compositions but different number of tokens. uint256 bptAmountOut = Math.mul(invariantAfterJoin, _getTotalTokens()); _lastInvariant = invariantAfterJoin; return (bptAmountOut, amountsIn); } // Join function _onJoinPool( bytes32, address, address, uint256[] memory balances, uint256, uint256 protocolSwapFeePercentage, bytes memory userData ) internal virtual override whenNotPaused returns ( uint256, uint256[] memory, uint256[] memory ) { // All joins are disabled while the contract is paused. uint256[] memory normalizedWeights = _normalizedWeights(); // Due protocol swap fee amounts are computed by measuring the growth of the invariant between the previous join // or exit event and now - the invariant's growth is due exclusively to swap fees. This avoids spending gas // computing them on each individual swap uint256 invariantBeforeJoin = WeightedMath._calculateInvariant(normalizedWeights, balances); uint256[] memory dueProtocolFeeAmounts = _getDueProtocolFeeAmounts( balances, normalizedWeights, _lastInvariant, invariantBeforeJoin, protocolSwapFeePercentage ); // Update current balances by subtracting the protocol fee amounts _mutateAmounts(balances, dueProtocolFeeAmounts, FixedPoint.sub); (uint256 bptAmountOut, uint256[] memory amountsIn) = _doJoin(balances, normalizedWeights, userData); // Update the invariant with the balances the Pool will have after the join, in order to compute the // protocol swap fee amounts due in future joins and exits. _lastInvariant = _invariantAfterJoin(balances, amountsIn, normalizedWeights); return (bptAmountOut, amountsIn, dueProtocolFeeAmounts); } function _doJoin( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view returns (uint256, uint256[] memory) { JoinKind kind = userData.joinKind(); if (kind == JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT) { return _joinExactTokensInForBPTOut(balances, normalizedWeights, userData); } else if (kind == JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT) { return _joinTokenInForExactBPTOut(balances, normalizedWeights, userData); } else { _revert(Errors.UNHANDLED_JOIN_KIND); } } function _joinExactTokensInForBPTOut( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view returns (uint256, uint256[] memory) { (uint256[] memory amountsIn, uint256 minBPTAmountOut) = userData.exactTokensInForBptOut(); InputHelpers.ensureInputLengthMatch(_getTotalTokens(), amountsIn.length); _upscaleArray(amountsIn, _scalingFactors()); uint256 bptAmountOut = WeightedMath._calcBptOutGivenExactTokensIn( balances, normalizedWeights, amountsIn, totalSupply(), _swapFeePercentage ); _require(bptAmountOut >= minBPTAmountOut, Errors.BPT_OUT_MIN_AMOUNT); return (bptAmountOut, amountsIn); } function _joinTokenInForExactBPTOut( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view returns (uint256, uint256[] memory) { (uint256 bptAmountOut, uint256 tokenIndex) = userData.tokenInForExactBptOut(); // Note that there is no maximum amountIn parameter: this is handled by `IVault.joinPool`. _require(tokenIndex < _getTotalTokens(), Errors.OUT_OF_BOUNDS); uint256[] memory amountsIn = new uint256[](_getTotalTokens()); amountsIn[tokenIndex] = WeightedMath._calcTokenInGivenExactBptOut( balances[tokenIndex], normalizedWeights[tokenIndex], bptAmountOut, totalSupply(), _swapFeePercentage ); return (bptAmountOut, amountsIn); } // Exit function _onExitPool( bytes32, address, address, uint256[] memory balances, uint256, uint256 protocolSwapFeePercentage, bytes memory userData ) internal virtual override returns ( uint256 bptAmountIn, uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts ) { // Exits are not completely disabled while the contract is paused: proportional exits (exact BPT in for tokens // out) remain functional. uint256[] memory normalizedWeights = _normalizedWeights(); if (_isNotPaused()) { // Due protocol swap fee amounts are computed by measuring the growth of the invariant between the previous // join or exit event and now - the invariant's growth is due exclusively to swap fees. This avoids // spending gas calculating the fees on each individual swap. uint256 invariantBeforeExit = WeightedMath._calculateInvariant(normalizedWeights, balances); dueProtocolFeeAmounts = _getDueProtocolFeeAmounts( balances, normalizedWeights, _lastInvariant, invariantBeforeExit, protocolSwapFeePercentage ); // Update current balances by subtracting the protocol fee amounts _mutateAmounts(balances, dueProtocolFeeAmounts, FixedPoint.sub); } else { // If the contract is paused, swap protocol fee amounts are not charged to avoid extra calculations and // reduce the potential for errors. dueProtocolFeeAmounts = new uint256[](_getTotalTokens()); } (bptAmountIn, amountsOut) = _doExit(balances, normalizedWeights, userData); // Update the invariant with the balances the Pool will have after the exit, in order to compute the // protocol swap fees due in future joins and exits. _lastInvariant = _invariantAfterExit(balances, amountsOut, normalizedWeights); return (bptAmountIn, amountsOut, dueProtocolFeeAmounts); } function _doExit( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view returns (uint256, uint256[] memory) { ExitKind kind = userData.exitKind(); if (kind == ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { return _exitExactBPTInForTokenOut(balances, normalizedWeights, userData); } else if (kind == ExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT) { return _exitExactBPTInForTokensOut(balances, userData); } else { // ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT return _exitBPTInForExactTokensOut(balances, normalizedWeights, userData); } } function _exitExactBPTInForTokenOut( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view whenNotPaused returns (uint256, uint256[] memory) { // This exit function is disabled if the contract is paused. (uint256 bptAmountIn, uint256 tokenIndex) = userData.exactBptInForTokenOut(); // Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`. _require(tokenIndex < _getTotalTokens(), Errors.OUT_OF_BOUNDS); // We exit in a single token, so we initialize amountsOut with zeros uint256[] memory amountsOut = new uint256[](_getTotalTokens()); // And then assign the result to the selected token amountsOut[tokenIndex] = WeightedMath._calcTokenOutGivenExactBptIn( balances[tokenIndex], normalizedWeights[tokenIndex], bptAmountIn, totalSupply(), _swapFeePercentage ); return (bptAmountIn, amountsOut); } function _exitExactBPTInForTokensOut(uint256[] memory balances, bytes memory userData) private view returns (uint256, uint256[] memory) { // This exit function is the only one that is not disabled if the contract is paused: it remains unrestricted // in an attempt to provide users with a mechanism to retrieve their tokens in case of an emergency. // This particular exit function is the only one that remains available because it is the simplest one, and // therefore the one with the lowest likelihood of errors. uint256 bptAmountIn = userData.exactBptInForTokensOut(); // Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`. uint256[] memory amountsOut = WeightedMath._calcTokensOutGivenExactBptIn(balances, bptAmountIn, totalSupply()); return (bptAmountIn, amountsOut); } function _exitBPTInForExactTokensOut( uint256[] memory balances, uint256[] memory normalizedWeights, bytes memory userData ) private view whenNotPaused returns (uint256, uint256[] memory) { // This exit function is disabled if the contract is paused. (uint256[] memory amountsOut, uint256 maxBPTAmountIn) = userData.bptInForExactTokensOut(); InputHelpers.ensureInputLengthMatch(amountsOut.length, _getTotalTokens()); _upscaleArray(amountsOut, _scalingFactors()); uint256 bptAmountIn = WeightedMath._calcBptInGivenExactTokensOut( balances, normalizedWeights, amountsOut, totalSupply(), _swapFeePercentage ); _require(bptAmountIn <= maxBPTAmountIn, Errors.BPT_IN_MAX_AMOUNT); return (bptAmountIn, amountsOut); } // Helpers function _getDueProtocolFeeAmounts( uint256[] memory balances, uint256[] memory normalizedWeights, uint256 previousInvariant, uint256 currentInvariant, uint256 protocolSwapFeePercentage ) private view returns (uint256[] memory) { // Initialize with zeros uint256[] memory dueProtocolFeeAmounts = new uint256[](_getTotalTokens()); // Early return if the protocol swap fee percentage is zero, saving gas. if (protocolSwapFeePercentage == 0) { return dueProtocolFeeAmounts; } // The protocol swap fees are always paid using the token with the largest weight in the Pool. As this is the // token that is expected to have the largest balance, using it to pay fees should not unbalance the Pool. dueProtocolFeeAmounts[_maxWeightTokenIndex] = WeightedMath._calcDueTokenProtocolSwapFeeAmount( balances[_maxWeightTokenIndex], normalizedWeights[_maxWeightTokenIndex], previousInvariant, currentInvariant, protocolSwapFeePercentage ); return dueProtocolFeeAmounts; } /** * @dev Returns the value of the invariant given `balances`, assuming they are increased by `amountsIn`. All * amounts are expected to be upscaled. */ function _invariantAfterJoin( uint256[] memory balances, uint256[] memory amountsIn, uint256[] memory normalizedWeights ) private view returns (uint256) { _mutateAmounts(balances, amountsIn, FixedPoint.add); return WeightedMath._calculateInvariant(normalizedWeights, balances); } function _invariantAfterExit( uint256[] memory balances, uint256[] memory amountsOut, uint256[] memory normalizedWeights ) private view returns (uint256) { _mutateAmounts(balances, amountsOut, FixedPoint.sub); return WeightedMath._calculateInvariant(normalizedWeights, balances); } /** * @dev Mutates `amounts` by applying `mutation` with each entry in `arguments`. * * Equivalent to `amounts = amounts.map(mutation)`. */ function _mutateAmounts( uint256[] memory toMutate, uint256[] memory arguments, function(uint256, uint256) pure returns (uint256) mutation ) private view { for (uint256 i = 0; i < _getTotalTokens(); ++i) { toMutate[i] = mutation(toMutate[i], arguments[i]); } } /** * @dev This function returns the appreciation of one BPT relative to the * underlying tokens. This starts at 1 when the pool is created and grows over time */ function getRate() public view returns (uint256) { // The initial BPT supply is equal to the invariant times the number of tokens. return Math.mul(getInvariant(), _getTotalTokens()).divDown(totalSupply()); } }
// 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; pragma experimental ABIEncoderV2; import "../../vault/interfaces/IVault.sol"; import "../factories/BasePoolFactory.sol"; import "../factories/FactoryWidePauseWindow.sol"; import "./WeightedPool.sol"; contract WeightedPoolFactory is BasePoolFactory, FactoryWidePauseWindow { constructor(IVault vault) BasePoolFactory(vault) { // solhint-disable-previous-line no-empty-blocks } /** * @dev Deploys a new `WeightedPool`. */ function create( string memory name, string memory symbol, IERC20[] memory tokens, uint256[] memory weights, uint256 swapFeePercentage, address owner ) external returns (address) { (uint256 pauseWindowDuration, uint256 bufferPeriodDuration) = getPauseConfiguration(); address pool = address( new WeightedPool( getVault(), name, symbol, tokens, weights, swapFeePercentage, pauseWindowDuration, bufferPeriodDuration, owner ) ); _register(pool); return pool; } }
// 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 "../../lib/openzeppelin/IERC20.sol"; import "./IWETH.sol"; import "./IAsset.sol"; import "./IAuthorizer.sol"; import "./IFlashLoanRecipient.sol"; import "../ProtocolFeesCollector.sol"; import "../../lib/helpers/ISignaturesValidator.sol"; import "../../lib/helpers/ITemporarilyPausable.sol"; pragma solidity ^0.7.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 { // 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 (ProtocolFeesCollector); /** * @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; pragma experimental ABIEncoderV2; import "../../vault/interfaces/IVault.sol"; import "../../vault/interfaces/IBasePool.sol"; /** * @dev Base contract for Pool factories. * * Pools are deployed from factories to allow third parties to reason about them. Unknown Pools may have arbitrary * logic: being able to assert that a Pool's behavior follows certain rules (those imposed by the contracts created by * the factory) is very powerful. */ abstract contract BasePoolFactory { IVault private immutable _vault; mapping(address => bool) private _isPoolFromFactory; event PoolCreated(address indexed pool); constructor(IVault vault) { _vault = vault; } /** * @dev Returns the Vault's address. */ function getVault() public view returns (IVault) { return _vault; } /** * @dev Returns true if `pool` was created by this factory. */ function isPoolFromFactory(address pool) external view returns (bool) { return _isPoolFromFactory[pool]; } /** * @dev Registers a new created pool. * * Emits a `PoolCreated` event. */ function _register(address pool) internal { _isPoolFromFactory[pool] = true; emit PoolCreated(pool); } }
// 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; pragma experimental ABIEncoderV2; /** * @dev Utility to create Pool factories for Pools that use the `TemporarilyPausable` contract. * * By calling `TemporarilyPausable`'s constructor with the result of `getPauseConfiguration`, all Pools created by this * factory will share the same Pause Window end time, after which both old and new Pools will not be pausable. */ contract FactoryWidePauseWindow { // This contract relies on timestamps in a similar way as `TemporarilyPausable` does - the same caveats apply. // solhint-disable not-rely-on-time uint256 private constant _INITIAL_PAUSE_WINDOW_DURATION = 90 days; uint256 private constant _BUFFER_PERIOD_DURATION = 30 days; // Time when the pause window for all created Pools expires, and the pause window duration of new Pools becomes // zero. uint256 private immutable _poolsPauseWindowEndTime; constructor() { _poolsPauseWindowEndTime = block.timestamp + _INITIAL_PAUSE_WINDOW_DURATION; } /** * @dev Returns the current `TemporarilyPausable` configuration that will be applied to Pools created by this * factory. * * `pauseWindowDuration` will decrease over time until it reaches zero, at which point both it and * `bufferPeriodDuration` will be zero forever, meaning deployed Pools will not be pausable. */ function getPauseConfiguration() public view returns (uint256 pauseWindowDuration, uint256 bufferPeriodDuration) { uint256 currentTime = block.timestamp; if (currentTime < _poolsPauseWindowEndTime) { // The buffer period is always the same since its duration is related to how much time is needed to respond // to a potential emergency. The Pause Window duration however decreases as the end time approaches. pauseWindowDuration = _poolsPauseWindowEndTime - currentTime; // No need for checked arithmetic. bufferPeriodDuration = _BUFFER_PERIOD_DURATION; } else { // After the end time, newly created Pools have no Pause Window, nor Buffer Period (since they are not // pausable in the first place). pauseWindowDuration = 0; bufferPeriodDuration = 0; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.7.0; import "../../lib/openzeppelin/IERC20.sol"; /** * @dev Interface for the WETH token contract used internally for wrapping and unwrapping, to support * sending and receiving ETH in joins, swaps, and internal balance deposits and withdrawals. */ interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 amount) 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; /** * @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; 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; // Inspired by Aave Protocol's IFlashLoanReceiver. import "../../lib/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; pragma experimental ABIEncoderV2; import "../lib/openzeppelin/IERC20.sol"; import "../lib/helpers/InputHelpers.sol"; import "../lib/helpers/Authentication.sol"; import "../lib/openzeppelin/ReentrancyGuard.sol"; import "../lib/openzeppelin/SafeERC20.sol"; import "./interfaces/IVault.sol"; import "./interfaces/IAuthorizer.sol"; /** * @dev This an auxiliary contract to the Vault, deployed by it during construction. It offloads some of the tasks the * Vault performs to reduce its overall bytecode size. * * The current values for all protocol fee percentages are stored here, and any tokens charged as protocol fees are * sent to this contract, where they may be withdrawn by authorized entities. All authorization tasks are delegated * to the Vault's own authorizer. */ contract ProtocolFeesCollector is Authentication, ReentrancyGuard { using SafeERC20 for IERC20; // Absolute maximum fee percentages (1e18 = 100%, 1e16 = 1%). uint256 private constant _MAX_PROTOCOL_SWAP_FEE_PERCENTAGE = 50e16; // 50% uint256 private constant _MAX_PROTOCOL_FLASH_LOAN_FEE_PERCENTAGE = 1e16; // 1% IVault public immutable vault; // All fee percentages are 18-decimal fixed point numbers. // The swap fee is charged whenever a swap occurs, as a percentage of the fee charged by the Pool. These are not // actually charged on each individual swap: the `Vault` relies on the Pools being honest and reporting fees due // when users join and exit them. uint256 private _swapFeePercentage; // The flash loan fee is charged whenever a flash loan occurs, as a percentage of the tokens lent. uint256 private _flashLoanFeePercentage; event SwapFeePercentageChanged(uint256 newSwapFeePercentage); event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage); constructor(IVault _vault) // The ProtocolFeesCollector is a singleton, so it simply uses its own address to disambiguate action // identifiers. Authentication(bytes32(uint256(address(this)))) { vault = _vault; } function withdrawCollectedFees( IERC20[] calldata tokens, uint256[] calldata amounts, address recipient ) external nonReentrant authenticate { InputHelpers.ensureInputLengthMatch(tokens.length, amounts.length); for (uint256 i = 0; i < tokens.length; ++i) { IERC20 token = tokens[i]; uint256 amount = amounts[i]; token.safeTransfer(recipient, amount); } } function setSwapFeePercentage(uint256 newSwapFeePercentage) external authenticate { _require(newSwapFeePercentage <= _MAX_PROTOCOL_SWAP_FEE_PERCENTAGE, Errors.SWAP_FEE_PERCENTAGE_TOO_HIGH); _swapFeePercentage = newSwapFeePercentage; emit SwapFeePercentageChanged(newSwapFeePercentage); } function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external authenticate { _require( newFlashLoanFeePercentage <= _MAX_PROTOCOL_FLASH_LOAN_FEE_PERCENTAGE, Errors.FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH ); _flashLoanFeePercentage = newFlashLoanFeePercentage; emit FlashLoanFeePercentageChanged(newFlashLoanFeePercentage); } function getSwapFeePercentage() external view returns (uint256) { return _swapFeePercentage; } function getFlashLoanFeePercentage() external view returns (uint256) { return _flashLoanFeePercentage; } function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts) { feeAmounts = new uint256[](tokens.length); for (uint256 i = 0; i < tokens.length; ++i) { feeAmounts[i] = tokens[i].balanceOf(address(this)); } } function getAuthorizer() external view returns (IAuthorizer) { return _getAuthorizer(); } function _canPerform(bytes32 actionId, address account) internal view override returns (bool) { return _getAuthorizer().canPerform(actionId, account, address(this)); } function _getAuthorizer() internal view 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; /** * @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; /** * @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; import "../openzeppelin/IERC20.sol"; import "./BalancerErrors.sol"; import "../../vault/interfaces/IAsset.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(IAsset[] memory array) internal pure { address[] memory addressArray; // solhint-disable-next-line no-inline-assembly assembly { addressArray := array } ensureArrayIsSorted(addressArray); } 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 "./BalancerErrors.sol"; import "./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: MIT pragma solidity ^0.7.0; import "../helpers/BalancerErrors.sol"; // 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. /** * @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 pragma solidity ^0.7.0; import "../helpers/BalancerErrors.sol"; import "./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 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. (bool success, bytes memory returndata) = token.call(data); // If the low-level call didn't succeed we return whatever was returned from it. 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: 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; // solhint-disable /** * @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) pure { if (!condition) _revert(errorCode); } /** * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported. */ function _revert(uint256 errorCode) pure { // 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. The "BAL#" part is a known constant // (0x42414c23): we simply 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 revertReason := shl(200, add(0x42414c23000000, 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; // 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; // 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; // 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; // 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; }
// 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; 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; 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). `currentBalances` 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. `currentBalances` 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); }
// 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; pragma experimental ABIEncoderV2; import "../../lib/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; import "./LogExpMath.sol"; import "../helpers/BalancerErrors.sol"; /* solhint-disable private-vars-leading-underscore */ library FixedPoint { uint256 internal constant ONE = 1e18; // 18 decimal places uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14) // Minimum base for the power function when the exponent is 'free' (larger than ONE). uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18; function add(uint256 a, uint256 b) internal pure returns (uint256) { // Fixed Point addition is the same as regular checked addition uint256 c = a + b; _require(c >= a, Errors.ADD_OVERFLOW); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { // Fixed Point addition is the same as regular checked addition _require(b <= a, Errors.SUB_OVERFLOW); uint256 c = a - b; return c; } function mulDown(uint256 a, uint256 b) internal pure returns (uint256) { uint256 product = a * b; _require(a == 0 || product / a == b, Errors.MUL_OVERFLOW); return product / ONE; } function mulUp(uint256 a, uint256 b) internal pure returns (uint256) { uint256 product = a * b; _require(a == 0 || product / a == b, Errors.MUL_OVERFLOW); if (product == 0) { return 0; } else { // The traditional divUp formula is: // divUp(x, y) := (x + y - 1) / y // To avoid intermediate overflow in the addition, we distribute the division and get: // divUp(x, y) := (x - 1) / y + 1 // Note that this requires x != 0, which we already tested for. return ((product - 1) / ONE) + 1; } } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { _require(b != 0, Errors.ZERO_DIVISION); if (a == 0) { return 0; } else { uint256 aInflated = a * ONE; _require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow return aInflated / b; } } function divUp(uint256 a, uint256 b) internal pure returns (uint256) { _require(b != 0, Errors.ZERO_DIVISION); if (a == 0) { return 0; } else { uint256 aInflated = a * ONE; _require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow // The traditional divUp formula is: // divUp(x, y) := (x + y - 1) / y // To avoid intermediate overflow in the addition, we distribute the division and get: // divUp(x, y) := (x - 1) / y + 1 // Note that this requires x != 0, which we already tested for. return ((aInflated - 1) / b) + 1; } } /** * @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above * the true value (that is, the error function expected - actual is always positive). */ function powDown(uint256 x, uint256 y) internal pure returns (uint256) { uint256 raw = LogExpMath.pow(x, y); uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1); if (raw < maxError) { return 0; } else { return sub(raw, maxError); } } /** * @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below * the true value (that is, the error function expected - actual is always negative). */ function powUp(uint256 x, uint256 y) internal pure returns (uint256) { uint256 raw = LogExpMath.pow(x, y); uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1); return add(raw, maxError); } /** * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1. * * Useful when computing the complement for values with some level of relative error, as it strips this error and * prevents intermediate negative values. */ function complement(uint256 x) internal pure returns (uint256) { return (x < ONE) ? (ONE - x) : 0; } }
// SPDX-License-Identifier: 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; pragma experimental ABIEncoderV2; import "./BasePool.sol"; import "../vault/interfaces/IMinimalSwapInfoPool.sol"; /** * @dev Extension of `BasePool`, adding a handler for `IMinimalSwapInfoPool.onSwap`. * * Derived contracts must implement `_onSwapGivenIn` and `_onSwapGivenOut` along with `BasePool`'s virtual functions. */ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { constructor( IVault vault, string memory name, string memory symbol, IERC20[] memory tokens, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner ) BasePool( vault, tokens.length == 2 ? IVault.PoolSpecialization.TWO_TOKEN : IVault.PoolSpecialization.MINIMAL_SWAP_INFO, name, symbol, tokens, swapFeePercentage, pauseWindowDuration, bufferPeriodDuration, owner ) { // solhint-disable-previous-line no-empty-blocks } // Swap Hooks function onSwap( SwapRequest memory request, uint256 balanceTokenIn, uint256 balanceTokenOut ) external view virtual override returns (uint256) { uint256 scalingFactorTokenIn = _scalingFactor(request.tokenIn); uint256 scalingFactorTokenOut = _scalingFactor(request.tokenOut); if (request.kind == IVault.SwapKind.GIVEN_IN) { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. request.amount = _subtractSwapFeeAmount(request.amount); // All token amounts are upscaled. balanceTokenIn = _upscale(balanceTokenIn, scalingFactorTokenIn); balanceTokenOut = _upscale(balanceTokenOut, scalingFactorTokenOut); request.amount = _upscale(request.amount, scalingFactorTokenIn); uint256 amountOut = _onSwapGivenIn(request, balanceTokenIn, balanceTokenOut); // amountOut tokens are exiting the Pool, so we round down. return _downscaleDown(amountOut, scalingFactorTokenOut); } else { // All token amounts are upscaled. balanceTokenIn = _upscale(balanceTokenIn, scalingFactorTokenIn); balanceTokenOut = _upscale(balanceTokenOut, scalingFactorTokenOut); request.amount = _upscale(request.amount, scalingFactorTokenOut); uint256 amountIn = _onSwapGivenOut(request, balanceTokenIn, balanceTokenOut); // amountIn tokens are entering the Pool, so we round up. amountIn = _downscaleUp(amountIn, scalingFactorTokenIn); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. return _addSwapFeeAmount(amountIn); } } /* * @dev Called when a swap with the Pool occurs, where the amount of tokens entering the Pool is known. * * Returns the amount of tokens that will be taken from the Pool in return. * * All amounts inside `swapRequest`, `balanceTokenIn` and `balanceTokenOut` are upscaled. The swap fee has already * been deducted from `swapRequest.amount`. * * The return value is also considered upscaled, and will be downscaled (rounding down) before returning it to the * Vault. */ function _onSwapGivenIn( SwapRequest memory swapRequest, uint256 balanceTokenIn, uint256 balanceTokenOut ) internal view virtual returns (uint256); /* * @dev Called when a swap with the Pool occurs, where the amount of tokens exiting the Pool is known. * * Returns the amount of tokens that will be granted to the Pool in return. * * All amounts inside `swapRequest`, `balanceTokenIn` and `balanceTokenOut` are upscaled. * * The return value is also considered upscaled, and will be downscaled (rounding up) before applying the swap fee * and returning it to the Vault. */ function _onSwapGivenOut( SwapRequest memory swapRequest, uint256 balanceTokenIn, uint256 balanceTokenOut ) internal view virtual 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; import "../../lib/math/FixedPoint.sol"; import "../../lib/math/Math.sol"; import "../../lib/helpers/InputHelpers.sol"; /* solhint-disable private-vars-leading-underscore */ contract WeightedMath { using FixedPoint for uint256; // A minimum normalized weight imposes a maximum weight ratio. We need this due to limitations in the // implementation of the power function, as these ratios are often exponents. uint256 internal constant _MIN_WEIGHT = 0.01e18; // Having a minimum normalized weight imposes a limit on the maximum number of tokens; // i.e., the largest possible pool is one where all tokens have exactly the minimum weight. uint256 internal constant _MAX_WEIGHTED_TOKENS = 100; // Pool limits that arise from limitations in the fixed point power function (and the imposed 1:100 maximum weight // ratio). // Swap limits: amounts swapped may not be larger than this percentage of total balance. uint256 internal constant _MAX_IN_RATIO = 0.3e18; uint256 internal constant _MAX_OUT_RATIO = 0.3e18; // Invariant growth limit: non-proportional joins cannot cause the invariant to increase by more than this ratio. uint256 internal constant _MAX_INVARIANT_RATIO = 3e18; // Invariant shrink limit: non-proportional exits cannot cause the invariant to decrease by less than this ratio. uint256 internal constant _MIN_INVARIANT_RATIO = 0.7e18; // Invariant is used to collect protocol swap fees by comparing its value between two times. // So we can round always to the same direction. It is also used to initiate the BPT amount // and, because there is a minimum BPT, we round down the invariant. function _calculateInvariant(uint256[] memory normalizedWeights, uint256[] memory balances) internal pure returns (uint256 invariant) { /********************************************************************************************** // invariant _____ // // wi = weight index i | | wi // // bi = balance index i | | bi ^ = i // // i = invariant // **********************************************************************************************/ invariant = FixedPoint.ONE; for (uint256 i = 0; i < normalizedWeights.length; i++) { invariant = invariant.mulDown(balances[i].powDown(normalizedWeights[i])); } _require(invariant > 0, Errors.ZERO_INVARIANT); } // Computes how many tokens can be taken out of a pool if `amountIn` are sent, given the // current balances and weights. function _calcOutGivenIn( uint256 balanceIn, uint256 weightIn, uint256 balanceOut, uint256 weightOut, uint256 amountIn ) internal pure returns (uint256) { /********************************************************************************************** // outGivenIn // // aO = amountOut // // bO = balanceOut // // bI = balanceIn / / bI \ (wI / wO) \ // // aI = amountIn aO = bO * | 1 - | -------------------------- | ^ | // // wI = weightIn \ \ ( bI + aI ) / / // // wO = weightOut // **********************************************************************************************/ // Amount out, so we round down overall. // The multiplication rounds down, and the subtrahend (power) rounds up (so the base rounds up too). // Because bI / (bI + aI) <= 1, the exponent rounds down. // Cannot exceed maximum in ratio _require(amountIn <= balanceIn.mulDown(_MAX_IN_RATIO), Errors.MAX_IN_RATIO); uint256 denominator = balanceIn.add(amountIn); uint256 base = balanceIn.divUp(denominator); uint256 exponent = weightIn.divDown(weightOut); uint256 power = base.powUp(exponent); return balanceOut.mulDown(power.complement()); } // Computes how many tokens must be sent to a pool in order to take `amountOut`, given the // current balances and weights. function _calcInGivenOut( uint256 balanceIn, uint256 weightIn, uint256 balanceOut, uint256 weightOut, uint256 amountOut ) internal pure returns (uint256) { /********************************************************************************************** // inGivenOut // // aO = amountOut // // bO = balanceOut // // bI = balanceIn / / bO \ (wO / wI) \ // // aI = amountIn aI = bI * | | -------------------------- | ^ - 1 | // // wI = weightIn \ \ ( bO - aO ) / / // // wO = weightOut // **********************************************************************************************/ // Amount in, so we round up overall. // The multiplication rounds up, and the power rounds up (so the base rounds up too). // Because b0 / (b0 - a0) >= 1, the exponent rounds up. // Cannot exceed maximum out ratio _require(amountOut <= balanceOut.mulDown(_MAX_OUT_RATIO), Errors.MAX_OUT_RATIO); uint256 base = balanceOut.divUp(balanceOut.sub(amountOut)); uint256 exponent = weightOut.divUp(weightIn); uint256 power = base.powUp(exponent); // Because the base is larger than one (and the power rounds up), the power should always be larger than one, so // the following subtraction should never revert. uint256 ratio = power.sub(FixedPoint.ONE); return balanceIn.mulUp(ratio); } function _calcBptOutGivenExactTokensIn( uint256[] memory balances, uint256[] memory normalizedWeights, uint256[] memory amountsIn, uint256 bptTotalSupply, uint256 swapFee ) internal pure returns (uint256) { // BPT out, so we round down overall. uint256[] memory balanceRatiosWithFee = new uint256[](amountsIn.length); uint256 invariantRatioWithFees = 0; for (uint256 i = 0; i < balances.length; i++) { balanceRatiosWithFee[i] = balances[i].add(amountsIn[i]).divDown(balances[i]); invariantRatioWithFees = invariantRatioWithFees.add(balanceRatiosWithFee[i].mulDown(normalizedWeights[i])); } uint256 invariantRatio = FixedPoint.ONE; for (uint256 i = 0; i < balances.length; i++) { uint256 amountInWithoutFee; if (balanceRatiosWithFee[i] > invariantRatioWithFees) { uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithFees.sub(FixedPoint.ONE)); uint256 taxableAmount = amountsIn[i].sub(nonTaxableAmount); amountInWithoutFee = nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE.sub(swapFee))); } else { amountInWithoutFee = amountsIn[i]; } uint256 balanceRatio = balances[i].add(amountInWithoutFee).divDown(balances[i]); invariantRatio = invariantRatio.mulDown(balanceRatio.powDown(normalizedWeights[i])); } if (invariantRatio >= FixedPoint.ONE) { return bptTotalSupply.mulDown(invariantRatio.sub(FixedPoint.ONE)); } else { return 0; } } function _calcTokenInGivenExactBptOut( uint256 balance, uint256 normalizedWeight, uint256 bptAmountOut, uint256 bptTotalSupply, uint256 swapFee ) internal pure returns (uint256) { /****************************************************************************************** // tokenInForExactBPTOut // // a = amountIn // // b = balance / / totalBPT + bptOut \ (1 / w) \ // // bptOut = bptAmountOut a = b * | | -------------------------- | ^ - 1 | // // bpt = totalBPT \ \ totalBPT / / // // w = weight // ******************************************************************************************/ // Token in, so we round up overall. // Calculate the factor by which the invariant will increase after minting BPTAmountOut uint256 invariantRatio = bptTotalSupply.add(bptAmountOut).divUp(bptTotalSupply); _require(invariantRatio <= _MAX_INVARIANT_RATIO, Errors.MAX_OUT_BPT_FOR_TOKEN_IN); // Calculate by how much the token balance has to increase to match the invariantRatio uint256 balanceRatio = invariantRatio.powUp(FixedPoint.ONE.divUp(normalizedWeight)); uint256 amountInWithoutFee = balance.mulUp(balanceRatio.sub(FixedPoint.ONE)); // We can now compute how much extra balance is being deposited and used in virtual swaps, and charge swap fees // accordingly. uint256 taxablePercentage = normalizedWeight.complement(); uint256 taxableAmount = amountInWithoutFee.mulUp(taxablePercentage); uint256 nonTaxableAmount = amountInWithoutFee.sub(taxableAmount); return nonTaxableAmount.add(taxableAmount.divUp(swapFee.complement())); } function _calcBptInGivenExactTokensOut( uint256[] memory balances, uint256[] memory normalizedWeights, uint256[] memory amountsOut, uint256 bptTotalSupply, uint256 swapFee ) internal pure returns (uint256) { // BPT in, so we round up overall. uint256[] memory balanceRatiosWithoutFee = new uint256[](amountsOut.length); uint256 invariantRatioWithoutFees = 0; for (uint256 i = 0; i < balances.length; i++) { balanceRatiosWithoutFee[i] = balances[i].sub(amountsOut[i]).divUp(balances[i]); invariantRatioWithoutFees = invariantRatioWithoutFees.add( balanceRatiosWithoutFee[i].mulUp(normalizedWeights[i]) ); } uint256 invariantRatio = FixedPoint.ONE; for (uint256 i = 0; i < balances.length; i++) { // Swap fees are typically charged on 'token in', but there is no 'token in' here, // o we apply it to 'token out'. // This results in slightly larger price impact. uint256 amountOutWithFee; if (invariantRatioWithoutFees > balanceRatiosWithoutFee[i]) { uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithoutFees.complement()); uint256 taxableAmount = amountsOut[i].sub(nonTaxableAmount); amountOutWithFee = nonTaxableAmount.add(taxableAmount.divUp(swapFee.complement())); } else { amountOutWithFee = amountsOut[i]; } uint256 balanceRatio = balances[i].sub(amountOutWithFee).divDown(balances[i]); invariantRatio = invariantRatio.mulDown(balanceRatio.powDown(normalizedWeights[i])); } return bptTotalSupply.mulUp(invariantRatio.complement()); } function _calcTokenOutGivenExactBptIn( uint256 balance, uint256 normalizedWeight, uint256 bptAmountIn, uint256 bptTotalSupply, uint256 swapFee ) internal pure returns (uint256) { /***************************************************************************************** // exactBPTInForTokenOut // // a = amountOut // // b = balance / / totalBPT - bptIn \ (1 / w) \ // // bptIn = bptAmountIn a = b * | 1 - | -------------------------- | ^ | // // bpt = totalBPT \ \ totalBPT / / // // w = weight // *****************************************************************************************/ // Token out, so we round down overall. The multiplication rounds down, but the power rounds up (so the base // rounds up). Because (totalBPT - bptIn) / totalBPT <= 1, the exponent rounds down. // Calculate the factor by which the invariant will decrease after burning BPTAmountIn uint256 invariantRatio = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply); _require(invariantRatio >= _MIN_INVARIANT_RATIO, Errors.MIN_BPT_IN_FOR_TOKEN_OUT); // Calculate by how much the token balance has to decrease to match invariantRatio uint256 balanceRatio = invariantRatio.powUp(FixedPoint.ONE.divDown(normalizedWeight)); // Because of rounding up, balanceRatio can be greater than one. Using complement prevents reverts. uint256 amountOutWithoutFee = balance.mulDown(balanceRatio.complement()); // We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result // in swap fees. uint256 taxablePercentage = normalizedWeight.complement(); // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it // to 'token out'. This results in slightly larger price impact. Fees are rounded up. uint256 taxableAmount = amountOutWithoutFee.mulUp(taxablePercentage); uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount); return nonTaxableAmount.add(taxableAmount.mulDown(swapFee.complement())); } function _calcTokensOutGivenExactBptIn( uint256[] memory balances, uint256 bptAmountIn, uint256 totalBPT ) internal pure returns (uint256[] memory) { /********************************************************************************************** // exactBPTInForTokensOut // // (per token) // // aO = amountOut / bptIn \ // // b = balance a0 = b * | --------------------- | // // bptIn = bptAmountIn \ totalBPT / // // bpt = totalBPT // **********************************************************************************************/ // Since we're computing an amount out, we round down overall. This means rounding down on both the // multiplication and division. uint256 bptRatio = bptAmountIn.divDown(totalBPT); uint256[] memory amountsOut = new uint256[](balances.length); for (uint256 i = 0; i < balances.length; i++) { amountsOut[i] = balances[i].mulDown(bptRatio); } return amountsOut; } function _calcDueTokenProtocolSwapFeeAmount( uint256 balance, uint256 normalizedWeight, uint256 previousInvariant, uint256 currentInvariant, uint256 protocolSwapFeePercentage ) internal pure returns (uint256) { /********************************************************************************* /* protocolSwapFeePercentage * balanceToken * ( 1 - (previousInvariant / currentInvariant) ^ (1 / weightToken)) *********************************************************************************/ if (currentInvariant <= previousInvariant) { // This shouldn't happen outside of rounding errors, but have this safeguard nonetheless to prevent the Pool // from entering a locked state in which joins and exits revert while computing accumulated swap fees. return 0; } // We round down to prevent issues in the Pool's accounting, even if it means paying slightly less in protocol // fees to the Vault. // Fee percentage and balance multiplications round down, while the subtrahend (power) rounds up (as does the // base). Because previousInvariant / currentInvariant <= 1, the exponent rounds down. uint256 base = previousInvariant.divUp(currentInvariant); uint256 exponent = FixedPoint.ONE.divDown(normalizedWeight); // Because the exponent is larger than one, the base of the power function has a lower bound. We cap to this // value to avoid numeric issues, which means in the extreme case (where the invariant growth is larger than // 1 / min exponent) the Pool will pay less in protocol fees than it should. base = Math.max(base, FixedPoint.MIN_POW_BASE_FREE_EXPONENT); uint256 power = base.powUp(exponent); uint256 tokenAccruedFees = balance.mulDown(power.complement()); return tokenAccruedFees.mulDown(protocolSwapFeePercentage); } }
// 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 "../../lib/openzeppelin/IERC20.sol"; import "./WeightedPool.sol"; library WeightedPoolUserDataHelpers { function joinKind(bytes memory self) internal pure returns (WeightedPool.JoinKind) { return abi.decode(self, (WeightedPool.JoinKind)); } function exitKind(bytes memory self) internal pure returns (WeightedPool.ExitKind) { return abi.decode(self, (WeightedPool.ExitKind)); } // Joins function initialAmountsIn(bytes memory self) internal pure returns (uint256[] memory amountsIn) { (, amountsIn) = abi.decode(self, (WeightedPool.JoinKind, uint256[])); } function exactTokensInForBptOut(bytes memory self) internal pure returns (uint256[] memory amountsIn, uint256 minBPTAmountOut) { (, amountsIn, minBPTAmountOut) = abi.decode(self, (WeightedPool.JoinKind, uint256[], uint256)); } function tokenInForExactBptOut(bytes memory self) internal pure returns (uint256 bptAmountOut, uint256 tokenIndex) { (, bptAmountOut, tokenIndex) = abi.decode(self, (WeightedPool.JoinKind, uint256, uint256)); } // Exits function exactBptInForTokenOut(bytes memory self) internal pure returns (uint256 bptAmountIn, uint256 tokenIndex) { (, bptAmountIn, tokenIndex) = abi.decode(self, (WeightedPool.ExitKind, uint256, uint256)); } function exactBptInForTokensOut(bytes memory self) internal pure returns (uint256 bptAmountIn) { (, bptAmountIn) = abi.decode(self, (WeightedPool.ExitKind, uint256)); } function bptInForExactTokensOut(bytes memory self) internal pure returns (uint256[] memory amountsOut, uint256 maxBPTAmountIn) { (, amountsOut, maxBPTAmountIn) = abi.decode(self, (WeightedPool.ExitKind, uint256[], uint256)); } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General internal License for more details. // You should have received a copy of the GNU General internal License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.7.0; import "../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 < 2**255, Errors.X_OUT_OF_BOUNDS); int256 x_int256 = int256(x); // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end. // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range. _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS); int256 y_int256 = int256(y); int256 logx_times_y; if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) { int256 ln_36_x = ln_36(x_int256); // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the // (downscaled) last 18 decimals. logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18); } else { logx_times_y = ln(x_int256) * y_int256; } logx_times_y /= ONE_18; // Finally, we compute exp(y * ln(x)) to arrive at x^y _require( MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT, Errors.PRODUCT_OUT_OF_BOUNDS ); return uint256(exp(logx_times_y)); } /** * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent. * * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`. */ function exp(int256 x) internal pure returns (int256) { _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT); if (x < 0) { // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT). // Fixed point division requires multiplying by ONE_18. return ((ONE_18 * ONE_18) / exp(-x)); } // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n, // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7 // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the // decomposition. // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this // decomposition, which will be lower than the smallest x_n. // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1. // We mutate x by subtracting x_n, making it the remainder of the decomposition. // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause // intermediate overflows. Instead we store them as plain integers, with 0 decimals. // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the // decomposition. // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct // it and compute the accumulated product. int256 firstAN; if (x >= x0) { x -= x0; firstAN = a0; } else if (x >= x1) { x -= x1; firstAN = a1; } else { firstAN = 1; // One with no decimal places } // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the // smaller terms. x *= 100; // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point // one. Recall that fixed point multiplication requires dividing by ONE_20. int256 product = ONE_20; if (x >= x2) { x -= x2; product = (product * a2) / ONE_20; } if (x >= x3) { x -= x3; product = (product * a3) / ONE_20; } if (x >= x4) { x -= x4; product = (product * a4) / ONE_20; } if (x >= x5) { x -= x5; product = (product * a5) / ONE_20; } if (x >= x6) { x -= x6; product = (product * a6) / ONE_20; } if (x >= x7) { x -= x7; product = (product * a7) / ONE_20; } if (x >= x8) { x -= x8; product = (product * a8) / ONE_20; } if (x >= x9) { x -= x9; product = (product * a9) / ONE_20; } // x10 and x11 are unnecessary here since we have high enough precision already. // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!). int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places. int256 term; // Each term in the sum, where the nth term is (x^n / n!). // The first term is simply x. term = x; seriesSum += term; // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number, // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not. term = ((term * x) / ONE_20) / 2; seriesSum += term; term = ((term * x) / ONE_20) / 3; seriesSum += term; term = ((term * x) / ONE_20) / 4; seriesSum += term; term = ((term * x) / ONE_20) / 5; seriesSum += term; term = ((term * x) / ONE_20) / 6; seriesSum += term; term = ((term * x) / ONE_20) / 7; seriesSum += term; term = ((term * x) / ONE_20) / 8; seriesSum += term; term = ((term * x) / ONE_20) / 9; seriesSum += term; term = ((term * x) / ONE_20) / 10; seriesSum += term; term = ((term * x) / ONE_20) / 11; seriesSum += term; term = ((term * x) / ONE_20) / 12; seriesSum += term; // 12 Taylor terms are sufficient for 18 decimal precision. // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication), // and then drop two digits to return an 18 decimal value. return (((product * seriesSum) / ONE_20) * firstAN) / 100; } /** * @dev 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 (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 Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument 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 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: 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; pragma experimental ABIEncoderV2; import "../lib/math/FixedPoint.sol"; import "../lib/helpers/InputHelpers.sol"; import "../lib/helpers/TemporarilyPausable.sol"; import "../lib/openzeppelin/ERC20.sol"; import "./BalancerPoolToken.sol"; import "./BasePoolAuthorization.sol"; import "../vault/interfaces/IVault.sol"; import "../vault/interfaces/IBasePool.sol"; // This contract relies on tons of immutable state variables to perform efficient lookup, without resorting to storage // reads. Because immutable arrays are not supported, we instead declare a fixed set of state variables plus a total // count, resulting in a large number of state variables. // solhint-disable max-states-count /** * @dev Reference implementation for the base layer of a Pool contract that manages a single Pool with an immutable set * of registered tokens, no Asset Managers, an admin-controlled swap fee percentage, and an emergency pause mechanism. * * Note that neither swap fees nor the pause mechanism are used by this contract. They are passed through so that * derived contracts can use them via the `_addSwapFeeAmount` and `_subtractSwapFeeAmount` functions, and the * `whenNotPaused` modifier. * * No admin permissions are checked here: instead, this contract delegates that to the Vault's own Authorizer. * * Because this contract doesn't implement the swap hooks, derived contracts should generally inherit from * BaseGeneralPool or BaseMinimalSwapInfoPool. Otherwise, subclasses must inherit from the corresponding interfaces * and implement the swap callbacks themselves. */ abstract contract BasePool is IBasePool, BasePoolAuthorization, BalancerPoolToken, TemporarilyPausable { using FixedPoint for uint256; uint256 private constant _MIN_TOKENS = 2; uint256 private constant _MAX_TOKENS = 8; // 1e18 corresponds to 1.0, or a 100% fee uint256 private constant _MIN_SWAP_FEE_PERCENTAGE = 1e12; // 0.0001% uint256 private constant _MAX_SWAP_FEE_PERCENTAGE = 1e17; // 10% uint256 private constant _MINIMUM_BPT = 1e6; uint256 internal _swapFeePercentage; IVault private immutable _vault; bytes32 private immutable _poolId; uint256 private immutable _totalTokens; IERC20 internal immutable _token0; IERC20 internal immutable _token1; IERC20 internal immutable _token2; IERC20 internal immutable _token3; IERC20 internal immutable _token4; IERC20 internal immutable _token5; IERC20 internal immutable _token6; IERC20 internal immutable _token7; // All token balances are normalized to behave as if the token had 18 decimals. We assume a token's decimals will // not change throughout its lifetime, and store the corresponding scaling factor for each at construction time. // These factors are always greater than or equal to one: tokens with more than 18 decimals are not supported. uint256 internal immutable _scalingFactor0; uint256 internal immutable _scalingFactor1; uint256 internal immutable _scalingFactor2; uint256 internal immutable _scalingFactor3; uint256 internal immutable _scalingFactor4; uint256 internal immutable _scalingFactor5; uint256 internal immutable _scalingFactor6; uint256 internal immutable _scalingFactor7; event SwapFeePercentageChanged(uint256 swapFeePercentage); constructor( IVault vault, IVault.PoolSpecialization specialization, string memory name, string memory symbol, IERC20[] memory tokens, uint256 swapFeePercentage, uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner ) // Base Pools are expected to be deployed using factories. By using the factory address as the action // disambiguator, we make all Pools deployed by the same factory share action identifiers. This allows for // simpler management of permissions (such as being able to manage granting the 'set fee percentage' action in // any Pool created by the same factory), while still making action identifiers unique among different factories // if the selectors match, preventing accidental errors. Authentication(bytes32(uint256(msg.sender))) BalancerPoolToken(name, symbol) BasePoolAuthorization(owner) TemporarilyPausable(pauseWindowDuration, bufferPeriodDuration) { _require(tokens.length >= _MIN_TOKENS, Errors.MIN_TOKENS); _require(tokens.length <= _MAX_TOKENS, Errors.MAX_TOKENS); // The Vault only requires the token list to be ordered for the Two Token Pools specialization. However, // to make the developer experience consistent, we are requiring this condition for all the native pools. // Also, since these Pools will register tokens only once, we can ensure the Pool tokens will follow the same // order. We rely on this property to make Pools simpler to write, as it lets us assume that the // order of token-specific parameters (such as token weights) will not change. InputHelpers.ensureArrayIsSorted(tokens); _setSwapFeePercentage(swapFeePercentage); bytes32 poolId = vault.registerPool(specialization); // Pass in zero addresses for Asset Managers vault.registerTokens(poolId, tokens, new address[](tokens.length)); // Set immutable state variables - these cannot be read from during construction _vault = vault; _poolId = poolId; _totalTokens = tokens.length; // Immutable variables cannot be initialized inside an if statement, so we must do conditional assignments _token0 = tokens.length > 0 ? tokens[0] : IERC20(0); _token1 = tokens.length > 1 ? tokens[1] : IERC20(0); _token2 = tokens.length > 2 ? tokens[2] : IERC20(0); _token3 = tokens.length > 3 ? tokens[3] : IERC20(0); _token4 = tokens.length > 4 ? tokens[4] : IERC20(0); _token5 = tokens.length > 5 ? tokens[5] : IERC20(0); _token6 = tokens.length > 6 ? tokens[6] : IERC20(0); _token7 = tokens.length > 7 ? tokens[7] : IERC20(0); _scalingFactor0 = tokens.length > 0 ? _computeScalingFactor(tokens[0]) : 0; _scalingFactor1 = tokens.length > 1 ? _computeScalingFactor(tokens[1]) : 0; _scalingFactor2 = tokens.length > 2 ? _computeScalingFactor(tokens[2]) : 0; _scalingFactor3 = tokens.length > 3 ? _computeScalingFactor(tokens[3]) : 0; _scalingFactor4 = tokens.length > 4 ? _computeScalingFactor(tokens[4]) : 0; _scalingFactor5 = tokens.length > 5 ? _computeScalingFactor(tokens[5]) : 0; _scalingFactor6 = tokens.length > 6 ? _computeScalingFactor(tokens[6]) : 0; _scalingFactor7 = tokens.length > 7 ? _computeScalingFactor(tokens[7]) : 0; } // Getters / Setters function getVault() public view returns (IVault) { return _vault; } function getPoolId() public view returns (bytes32) { return _poolId; } function _getTotalTokens() internal view returns (uint256) { return _totalTokens; } function getSwapFeePercentage() external view returns (uint256) { return _swapFeePercentage; } // Caller must be approved by the Vault's Authorizer function setSwapFeePercentage(uint256 swapFeePercentage) external virtual authenticate whenNotPaused { _setSwapFeePercentage(swapFeePercentage); } function _setSwapFeePercentage(uint256 swapFeePercentage) private { _require(swapFeePercentage >= _MIN_SWAP_FEE_PERCENTAGE, Errors.MIN_SWAP_FEE_PERCENTAGE); _require(swapFeePercentage <= _MAX_SWAP_FEE_PERCENTAGE, Errors.MAX_SWAP_FEE_PERCENTAGE); _swapFeePercentage = swapFeePercentage; emit SwapFeePercentageChanged(swapFeePercentage); } // Caller must be approved by the Vault's Authorizer function setPaused(bool paused) external authenticate { _setPaused(paused); } // Join / Exit Hooks modifier onlyVault(bytes32 poolId) { _require(msg.sender == address(getVault()), Errors.CALLER_NOT_VAULT); _require(poolId == getPoolId(), Errors.INVALID_POOL_ID); _; } function onJoinPool( bytes32 poolId, address sender, address recipient, uint256[] memory balances, uint256 lastChangeBlock, uint256 protocolSwapFeePercentage, bytes memory userData ) external virtual override onlyVault(poolId) returns (uint256[] memory, uint256[] memory) { uint256[] memory scalingFactors = _scalingFactors(); if (totalSupply() == 0) { (uint256 bptAmountOut, uint256[] memory amountsIn) = _onInitializePool(poolId, sender, recipient, userData); // On initialization, we lock _MINIMUM_BPT by minting it for the zero address. This BPT acts as a minimum // as it will never be burned, which reduces potential issues with rounding, and also prevents the Pool from // ever being fully drained. _require(bptAmountOut >= _MINIMUM_BPT, Errors.MINIMUM_BPT); _mintPoolTokens(address(0), _MINIMUM_BPT); _mintPoolTokens(recipient, bptAmountOut - _MINIMUM_BPT); // amountsIn are amounts entering the Pool, so we round up. _downscaleUpArray(amountsIn, scalingFactors); return (amountsIn, new uint256[](_getTotalTokens())); } else { _upscaleArray(balances, scalingFactors); (uint256 bptAmountOut, uint256[] memory amountsIn, uint256[] memory dueProtocolFeeAmounts) = _onJoinPool( poolId, sender, recipient, balances, lastChangeBlock, protocolSwapFeePercentage, userData ); // Note we no longer use `balances` after calling `_onJoinPool`, which may mutate it. _mintPoolTokens(recipient, bptAmountOut); // amountsIn are amounts entering the Pool, so we round up. _downscaleUpArray(amountsIn, scalingFactors); // dueProtocolFeeAmounts are amounts exiting the Pool, so we round down. _downscaleDownArray(dueProtocolFeeAmounts, scalingFactors); return (amountsIn, dueProtocolFeeAmounts); } } function onExitPool( bytes32 poolId, address sender, address recipient, uint256[] memory balances, uint256 lastChangeBlock, uint256 protocolSwapFeePercentage, bytes memory userData ) external virtual override onlyVault(poolId) returns (uint256[] memory, uint256[] memory) { uint256[] memory scalingFactors = _scalingFactors(); _upscaleArray(balances, scalingFactors); (uint256 bptAmountIn, uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts) = _onExitPool( poolId, sender, recipient, balances, lastChangeBlock, protocolSwapFeePercentage, userData ); // Note we no longer use `balances` after calling `_onExitPool`, which may mutate it. _burnPoolTokens(sender, bptAmountIn); // Both amountsOut and dueProtocolFeeAmounts are amounts exiting the Pool, so we round down. _downscaleDownArray(amountsOut, scalingFactors); _downscaleDownArray(dueProtocolFeeAmounts, scalingFactors); return (amountsOut, dueProtocolFeeAmounts); } // Query functions /** * @dev Returns the amount of BPT that would be granted to `recipient` if the `onJoinPool` hook were called by the * Vault with the same arguments, along with the number of tokens `sender` would have to supply. * * This function is not meant to be called directly, but rather from a helper contract that fetches current Vault * data, such as the protocol swap fee percentage and Pool balances. * * Like `IVault.queryBatchSwap`, this function is not view due to internal implementation details: the caller must * explicitly use eth_call instead of eth_sendTransaction. */ 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) { InputHelpers.ensureInputLengthMatch(balances.length, _getTotalTokens()); _queryAction( poolId, sender, recipient, balances, lastChangeBlock, protocolSwapFeePercentage, userData, _onJoinPool, _downscaleUpArray ); // The `return` opcode is executed directly inside `_queryAction`, so execution never reaches this statement, // and we don't need to return anything here - it just silences compiler warnings. return (bptOut, amountsIn); } /** * @dev Returns the amount of BPT that would be burned from `sender` if the `onExitPool` hook were called by the * Vault with the same arguments, along with the number of tokens `recipient` would receive. * * This function is not meant to be called directly, but rather from a helper contract that fetches current Vault * data, such as the protocol swap fee percentage and Pool balances. * * Like `IVault.queryBatchSwap`, this function is not view due to internal implementation details: the caller must * explicitly use eth_call instead of eth_sendTransaction. */ 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) { InputHelpers.ensureInputLengthMatch(balances.length, _getTotalTokens()); _queryAction( poolId, sender, recipient, balances, lastChangeBlock, protocolSwapFeePercentage, userData, _onExitPool, _downscaleDownArray ); // The `return` opcode is executed directly inside `_queryAction`, so execution never reaches this statement, // and we don't need to return anything here - it just silences compiler warnings. return (bptIn, amountsOut); } // Internal hooks to be overridden by derived contracts - all token amounts (except BPT) in these interfaces are // upscaled. /** * @dev Called when the Pool is joined for the first time; that is, when the BPT total supply is zero. * * Returns the amount of BPT to mint, and the token amounts the Pool will receive in return. * * Minted BPT will be sent to `recipient`, except for _MINIMUM_BPT, which will be deducted from this amount and sent * to the zero address instead. This will cause that BPT to remain forever locked there, preventing total BTP from * ever dropping below that value, and ensuring `_onInitializePool` can only be called once in the entire Pool's * lifetime. * * The tokens granted to the Pool will be transferred from `sender`. These amounts are considered upscaled and will * be downscaled (rounding up) before being returned to the Vault. */ function _onInitializePool( bytes32 poolId, address sender, address recipient, bytes memory userData ) internal virtual returns (uint256 bptAmountOut, uint256[] memory amountsIn); /** * @dev Called whenever the Pool is joined after the first initialization join (see `_onInitializePool`). * * Returns the amount of BPT to mint, the token amounts that the Pool will receive in return, and the number of * tokens to pay in protocol swap fees. * * Implementations of this function might choose to mutate the `balances` array to save gas (e.g. when * performing intermediate calculations, such as subtraction of due protocol fees). This can be done safely. * * Minted BPT will be sent to `recipient`. * * The tokens granted to the Pool will be transferred from `sender`. These amounts are considered upscaled and will * be downscaled (rounding up) before being returned to the Vault. * * Due protocol swap fees will be taken from the Pool's balance in the Vault (see `IBasePool.onJoinPool`). These * amounts are considered upscaled and will be downscaled (rounding down) before being returned to the Vault. */ function _onJoinPool( bytes32 poolId, address sender, address recipient, uint256[] memory balances, uint256 lastChangeBlock, uint256 protocolSwapFeePercentage, bytes memory userData ) internal virtual returns ( uint256 bptAmountOut, uint256[] memory amountsIn, uint256[] memory dueProtocolFeeAmounts ); /** * @dev Called whenever the Pool is exited. * * Returns the amount of BPT to burn, the token amounts for each Pool token that the Pool will grant in return, and * the number of tokens to pay in protocol swap fees. * * Implementations of this function might choose to mutate the `balances` array to save gas (e.g. when * performing intermediate calculations, such as subtraction of due protocol fees). This can be done safely. * * BPT will be burnt from `sender`. * * The Pool will grant tokens to `recipient`. These amounts are considered upscaled and will be downscaled * (rounding down) before being returned to the Vault. * * Due protocol swap fees will be taken from the Pool's balance in the Vault (see `IBasePool.onExitPool`). These * amounts are considered upscaled and will be downscaled (rounding down) before being returned to the Vault. */ function _onExitPool( bytes32 poolId, address sender, address recipient, uint256[] memory balances, uint256 lastChangeBlock, uint256 protocolSwapFeePercentage, bytes memory userData ) internal virtual returns ( uint256 bptAmountIn, uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts ); // Internal functions /** * @dev Adds swap fee amount to `amount`, returning a higher value. */ function _addSwapFeeAmount(uint256 amount) internal view returns (uint256) { // This returns amount + fee amount, so we round up (favoring a higher fee amount). return amount.divUp(_swapFeePercentage.complement()); } /** * @dev Subtracts swap fee amount from `amount`, returning a lower value. */ function _subtractSwapFeeAmount(uint256 amount) internal view returns (uint256) { // This returns amount - fee amount, so we round up (favoring a higher fee amount). uint256 feeAmount = amount.mulUp(_swapFeePercentage); return amount.sub(feeAmount); } // Scaling /** * @dev Returns a scaling factor that, when multiplied to a token amount for `token`, normalizes its balance as if * it had 18 decimals. */ function _computeScalingFactor(IERC20 token) private 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 10**decimalsDifference; } /** * @dev Returns the scaling factor for one of the Pool's tokens. Reverts if `token` is not a token registered by the * Pool. */ function _scalingFactor(IERC20 token) internal view returns (uint256) { // prettier-ignore if (token == _token0) { return _scalingFactor0; } else if (token == _token1) { return _scalingFactor1; } else if (token == _token2) { return _scalingFactor2; } else if (token == _token3) { return _scalingFactor3; } else if (token == _token4) { return _scalingFactor4; } else if (token == _token5) { return _scalingFactor5; } else if (token == _token6) { return _scalingFactor6; } else if (token == _token7) { return _scalingFactor7; } else { _revert(Errors.INVALID_TOKEN); } } /** * @dev Returns all the scaling factors in the same order as the registered tokens. The Vault will always * pass balances in this order when calling any of the Pool hooks */ function _scalingFactors() internal view returns (uint256[] memory) { uint256 totalTokens = _getTotalTokens(); uint256[] memory scalingFactors = new uint256[](totalTokens); // prettier-ignore { if (totalTokens > 0) { scalingFactors[0] = _scalingFactor0; } else { return scalingFactors; } if (totalTokens > 1) { scalingFactors[1] = _scalingFactor1; } else { return scalingFactors; } if (totalTokens > 2) { scalingFactors[2] = _scalingFactor2; } else { return scalingFactors; } if (totalTokens > 3) { scalingFactors[3] = _scalingFactor3; } else { return scalingFactors; } if (totalTokens > 4) { scalingFactors[4] = _scalingFactor4; } else { return scalingFactors; } if (totalTokens > 5) { scalingFactors[5] = _scalingFactor5; } else { return scalingFactors; } if (totalTokens > 6) { scalingFactors[6] = _scalingFactor6; } else { return scalingFactors; } if (totalTokens > 7) { scalingFactors[7] = _scalingFactor7; } else { return scalingFactors; } } return scalingFactors; } /** * @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) internal pure returns (uint256) { return Math.mul(amount, scalingFactor); } /** * @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) internal view { for (uint256 i = 0; i < _getTotalTokens(); ++i) { amounts[i] = Math.mul(amounts[i], scalingFactors[i]); } } /** * @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) internal pure returns (uint256) { return Math.divDown(amount, scalingFactor); } /** * @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) internal view { for (uint256 i = 0; i < _getTotalTokens(); ++i) { amounts[i] = Math.divDown(amounts[i], scalingFactors[i]); } } /** * @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) internal pure returns (uint256) { return Math.divUp(amount, scalingFactor); } /** * @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) internal view { for (uint256 i = 0; i < _getTotalTokens(); ++i) { amounts[i] = Math.divUp(amounts[i], scalingFactors[i]); } } function _getAuthorizer() internal view override returns (IAuthorizer) { // Access control management is delegated to the Vault's Authorizer. This lets Balancer Governance manage which // accounts can call permissioned functions: for example, to perform emergency pauses. // If the owner is delegated, then *all* permissioned functions, including `setSwapFeePercentage`, will be under // Governance control. return getVault().getAuthorizer(); } function _queryAction( bytes32 poolId, address sender, address recipient, uint256[] memory balances, uint256 lastChangeBlock, uint256 protocolSwapFeePercentage, bytes memory userData, function(bytes32, address, address, uint256[] memory, uint256, uint256, bytes memory) internal returns (uint256, uint256[] memory, uint256[] memory) _action, function(uint256[] memory, uint256[] memory) internal view _downscaleArray ) private { // This uses the same technique used by the Vault in queryBatchSwap. Refer to that function for a detailed // explanation. if (msg.sender != address(this)) { // We perform an external call to ourselves, forwarding the same calldata. In this call, the else clause of // the preceding if statement will be executed instead. // solhint-disable-next-line avoid-low-level-calls (bool success, ) = address(this).call(msg.data); // solhint-disable-next-line no-inline-assembly assembly { // This call should always revert to decode the bpt and token amounts from the revert reason switch success case 0 { // Note we are manually writing the memory slot 0. We can safely overwrite whatever is // stored there as we take full control of the execution and then immediately return. // We copy the first 4 bytes to check if it matches with the expected signature, otherwise // there was another revert reason and we should forward it. returndatacopy(0, 0, 0x04) let error := and(mload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000) // If the first 4 bytes don't match with the expected signature, we forward the revert reason. if eq(eq(error, 0x43adbafb00000000000000000000000000000000000000000000000000000000), 0) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } // The returndata contains the signature, followed by the raw memory representation of the // `bptAmount` and `tokenAmounts` (array: length + data). We need to return an ABI-encoded // representation of these. // An ABI-encoded response will include one additional field to indicate the starting offset of // the `tokenAmounts` array. The `bptAmount` will be laid out in the first word of the // returndata. // // In returndata: // [ signature ][ bptAmount ][ tokenAmounts length ][ tokenAmounts values ] // [ 4 bytes ][ 32 bytes ][ 32 bytes ][ (32 * length) bytes ] // // We now need to return (ABI-encoded values): // [ bptAmount ][ tokeAmounts offset ][ tokenAmounts length ][ tokenAmounts values ] // [ 32 bytes ][ 32 bytes ][ 32 bytes ][ (32 * length) bytes ] // We copy 32 bytes for the `bptAmount` from returndata into memory. // Note that we skip the first 4 bytes for the error signature returndatacopy(0, 0x04, 32) // The offsets are 32-bytes long, so the array of `tokenAmounts` will start after // the initial 64 bytes. mstore(0x20, 64) // We now copy the raw memory array for the `tokenAmounts` from returndata into memory. // Since bpt amount and offset take up 64 bytes, we start copying at address 0x40. We also // skip the first 36 bytes from returndata, which correspond to the signature plus bpt amount. returndatacopy(0x40, 0x24, sub(returndatasize(), 36)) // We finally return the ABI-encoded uint256 and the array, which has a total length equal to // the size of returndata, plus the 32 bytes of the offset but without the 4 bytes of the // error signature. return(0, add(returndatasize(), 28)) } default { // This call should always revert, but we fail nonetheless if that didn't happen invalid() } } } else { uint256[] memory scalingFactors = _scalingFactors(); _upscaleArray(balances, scalingFactors); (uint256 bptAmount, uint256[] memory tokenAmounts, ) = _action( poolId, sender, recipient, balances, lastChangeBlock, protocolSwapFeePercentage, userData ); _downscaleArray(tokenAmounts, scalingFactors); // solhint-disable-next-line no-inline-assembly assembly { // We will return a raw representation of `bptAmount` and `tokenAmounts` in memory, which is composed of // a 32-byte uint256, followed by a 32-byte for the array length, and finally the 32-byte uint256 values // Because revert expects a size in bytes, we multiply the array length (stored at `tokenAmounts`) by 32 let size := mul(mload(tokenAmounts), 32) // We store the `bptAmount` in the previous slot to the `tokenAmounts` array. We can make sure there // will be at least one available slot due to how the memory scratch space works. // We can safely overwrite whatever is stored in this slot as we will revert immediately after that. let start := sub(tokenAmounts, 0x20) mstore(start, bptAmount) // We send one extra value for the error signature "QueryError(uint256,uint256[])" which is 0x43adbafb // We use the previous slot to `bptAmount`. mstore(sub(start, 0x20), 0x0000000000000000000000000000000000000000000000000000000043adbafb) start := sub(start, 0x04) // When copying from `tokenAmounts` into returndata, we copy the additional 68 bytes to also return // the `bptAmount`, the array 's length, and the error signature. revert(start, add(size, 68)) } } } }
// 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; pragma experimental ABIEncoderV2; import "./IBasePool.sol"; /** * @dev Pool contracts with the MinimalSwapInfo or TwoToken specialization settings should implement this interface. * * This is called by the Vault when a user calls `IVault.swap` or `IVault.batchSwap` to swap with this Pool. * Returns the number of tokens the Pool will grant to the user in a 'given in' swap, or that the user will grant * to the pool in a 'given out' swap. * * This can often be implemented by a `view` function, since many pricing algorithms don't need to track state * changes in swaps. However, contracts implementing this in non-view functions should check that the caller is * indeed the Vault. */ interface IMinimalSwapInfoPool is IBasePool { function onSwap( SwapRequest memory swapRequest, uint256 currentBalanceTokenIn, uint256 currentBalanceTokenOut ) external returns (uint256 amount); }
// 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 "./BalancerErrors.sol"; import "./ITemporarilyPausable.sol"; /** * @dev Allows for a contract to be paused during an initial period after deployment, disabling functionality. Can be * used as an emergency switch in case a security vulnerability or threat is identified. * * The contract can only be paused during the Pause Window, a period that starts at deployment. It can also be * unpaused and repaused any number of times during this period. This is intended to serve as a safety measure: it lets * system managers react quickly to potentially dangerous situations, knowing that this action is reversible if careful * analysis later determines there was a false alarm. * * If the contract is paused when the Pause Window finishes, it will remain in the paused state through an additional * Buffer Period, after which it will be automatically unpaused forever. This is to ensure there is always enough time * to react to an emergency, even if the threat is discovered shortly before the Pause Window expires. * * Note that since the contract can only be paused within the Pause Window, unpausing during the Buffer Period is * irreversible. */ abstract contract TemporarilyPausable is ITemporarilyPausable { // The Pause Window and Buffer Period are timestamp-based: they should not be relied upon for sub-minute accuracy. // solhint-disable not-rely-on-time uint256 private constant _MAX_PAUSE_WINDOW_DURATION = 90 days; uint256 private constant _MAX_BUFFER_PERIOD_DURATION = 30 days; uint256 private immutable _pauseWindowEndTime; uint256 private immutable _bufferPeriodEndTime; bool private _paused; constructor(uint256 pauseWindowDuration, uint256 bufferPeriodDuration) { _require(pauseWindowDuration <= _MAX_PAUSE_WINDOW_DURATION, Errors.MAX_PAUSE_WINDOW_DURATION); _require(bufferPeriodDuration <= _MAX_BUFFER_PERIOD_DURATION, Errors.MAX_BUFFER_PERIOD_DURATION); uint256 pauseWindowEndTime = block.timestamp + pauseWindowDuration; _pauseWindowEndTime = pauseWindowEndTime; _bufferPeriodEndTime = pauseWindowEndTime + bufferPeriodDuration; } /** * @dev Reverts if the contract is paused. */ modifier whenNotPaused() { _ensureNotPaused(); _; } /** * @dev Returns the current contract pause status, as well as the end times of the Pause Window and Buffer * Period. */ function getPausedState() external view override returns ( bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime ) { paused = !_isNotPaused(); pauseWindowEndTime = _getPauseWindowEndTime(); bufferPeriodEndTime = _getBufferPeriodEndTime(); } /** * @dev Sets the pause state to `paused`. The contract can only be paused until the end of the Pause Window, and * unpaused until the end of the Buffer Period. * * Once the Buffer Period expires, this function reverts unconditionally. */ function _setPaused(bool paused) internal { if (paused) { _require(block.timestamp < _getPauseWindowEndTime(), Errors.PAUSE_WINDOW_EXPIRED); } else { _require(block.timestamp < _getBufferPeriodEndTime(), Errors.BUFFER_PERIOD_EXPIRED); } _paused = paused; emit PausedStateChanged(paused); } /** * @dev Reverts if the contract is paused. */ function _ensureNotPaused() internal view { _require(_isNotPaused(), Errors.PAUSED); } /** * @dev Returns true if the contract is unpaused. * * Once the Buffer Period expires, the gas cost of calling this function is reduced dramatically, as storage is no * longer accessed. */ function _isNotPaused() internal view returns (bool) { // After the Buffer Period, the (inexpensive) timestamp check short-circuits the storage access. return block.timestamp > _getBufferPeriodEndTime() || !_paused; } // These getters lead to reduced bytecode size by inlining the immutable variables in a single place. function _getPauseWindowEndTime() private view returns (uint256) { return _pauseWindowEndTime; } function _getBufferPeriodEndTime() private view returns (uint256) { return _bufferPeriodEndTime; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../helpers/BalancerErrors.sol"; import "./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}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @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 { _require(account != address(0), Errors.ERC20_MINT_TO_ZERO_ADDRESS); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _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_ALLOWANCE); _totalSupply = _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 { _require(owner != address(0), Errors.ERC20_APPROVE_FROM_ZERO_ADDRESS); _require(spender != address(0), Errors.ERC20_APPROVE_TO_ZERO_ADDRESS); _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 {} }
// 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 "../lib/math/Math.sol"; import "../lib/openzeppelin/IERC20.sol"; import "../lib/openzeppelin/IERC20Permit.sol"; import "../lib/openzeppelin/EIP712.sol"; /** * @title Highly opinionated token implementation * @author Balancer Labs * @dev * - Includes functions to increase and decrease allowance as a workaround * for the well-known issue with `approve`: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * - Allows for 'infinite allowance', where an allowance of 0xff..ff is not * decreased by calls to transferFrom * - Lets a token holder use `transferFrom` to send their own tokens, * without first setting allowance * - Emits 'Approval' events whenever allowance is changed by `transferFrom` */ contract BalancerPoolToken is IERC20, IERC20Permit, EIP712 { using Math for uint256; // State variables uint8 private constant _DECIMALS = 18; mapping(address => uint256) private _balance; mapping(address => mapping(address => uint256)) private _allowance; uint256 private _totalSupply; string private _name; string private _symbol; mapping(address => uint256) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPE_HASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); // Function declarations constructor(string memory tokenName, string memory tokenSymbol) EIP712(tokenName, "1") { _name = tokenName; _symbol = tokenSymbol; } // External functions function allowance(address owner, address spender) external view override returns (uint256) { return _allowance[owner][spender]; } function balanceOf(address account) external view override returns (uint256) { return _balance[account]; } function approve(address spender, uint256 amount) external override returns (bool) { _setAllowance(msg.sender, spender, amount); return true; } function increaseApproval(address spender, uint256 amount) external returns (bool) { _setAllowance(msg.sender, spender, _allowance[msg.sender][spender].add(amount)); return true; } function decreaseApproval(address spender, uint256 amount) external returns (bool) { uint256 currentAllowance = _allowance[msg.sender][spender]; if (amount >= currentAllowance) { _setAllowance(msg.sender, spender, 0); } else { _setAllowance(msg.sender, spender, currentAllowance.sub(amount)); } return true; } function transfer(address recipient, uint256 amount) external override returns (bool) { _move(msg.sender, recipient, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) external override returns (bool) { uint256 currentAllowance = _allowance[sender][msg.sender]; _require(msg.sender == sender || currentAllowance >= amount, Errors.INSUFFICIENT_ALLOWANCE); _move(sender, recipient, amount); if (msg.sender != sender && currentAllowance != uint256(-1)) { // Because of the previous require, we know that if msg.sender != sender then currentAllowance >= amount _setAllowance(sender, msg.sender, currentAllowance - amount); } return true; } function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { // solhint-disable-next-line not-rely-on-time _require(block.timestamp <= deadline, Errors.EXPIRED_PERMIT); uint256 nonce = _nonces[owner]; bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPE_HASH, owner, spender, value, nonce, deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ecrecover(hash, v, r, s); _require((signer != address(0)) && (signer == owner), Errors.INVALID_SIGNATURE); _nonces[owner] = nonce + 1; _setAllowance(owner, spender, value); } // Public functions function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public pure returns (uint8) { return _DECIMALS; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function nonces(address owner) external view override returns (uint256) { return _nonces[owner]; } // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } // Internal functions function _mintPoolTokens(address recipient, uint256 amount) internal { _balance[recipient] = _balance[recipient].add(amount); _totalSupply = _totalSupply.add(amount); emit Transfer(address(0), recipient, amount); } function _burnPoolTokens(address sender, uint256 amount) internal { uint256 currentBalance = _balance[sender]; _require(currentBalance >= amount, Errors.INSUFFICIENT_BALANCE); _balance[sender] = currentBalance - amount; _totalSupply = _totalSupply.sub(amount); emit Transfer(sender, address(0), amount); } function _move( address sender, address recipient, uint256 amount ) internal { uint256 currentBalance = _balance[sender]; _require(currentBalance >= amount, Errors.INSUFFICIENT_BALANCE); // Prohibit transfers to the zero address to avoid confusion with the // Transfer event emitted by `_burnPoolTokens` _require(recipient != address(0), Errors.ERC20_TRANSFER_TO_ZERO_ADDRESS); _balance[sender] = currentBalance - amount; _balance[recipient] = _balance[recipient].add(amount); emit Transfer(sender, recipient, amount); } // Private functions function _setAllowance( address owner, address spender, uint256 amount ) private { _allowance[owner][spender] = amount; emit Approval(owner, spender, amount); } }
// 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 "../lib/helpers/Authentication.sol"; import "../vault/interfaces/IAuthorizer.sol"; import "./BasePool.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 private 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 actionId) private view returns (bool) { // This implementation hardcodes the setSwapFeePercentage action identifier. return actionId == getActionId(BasePool.setSwapFeePercentage.selector); } function _getAuthorizer() internal view virtual returns (IAuthorizer); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../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.7.0; import "../helpers/BalancerErrors.sol"; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow checks. * Adapted from OpenZeppelin's SafeMath library */ library Math { /** * @dev Returns the addition of two unsigned integers of 256 bits, reverting on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; _require(c >= a, Errors.ADD_OVERFLOW); return c; } /** * @dev Returns the addition of two signed integers, reverting on overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; _require((b >= 0 && c >= a) || (b < 0 && c < a), Errors.ADD_OVERFLOW); return c; } /** * @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { _require(b <= a, Errors.SUB_OVERFLOW); uint256 c = a - b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; _require((b >= 0 && c <= a) || (b < 0 && c > a), Errors.SUB_OVERFLOW); return c; } /** * @dev Returns the largest of two numbers of 256 bits. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers of 256 bits. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a * b; _require(a == 0 || c / a == b, Errors.MUL_OVERFLOW); return c; } function divDown(uint256 a, uint256 b) internal pure returns (uint256) { _require(b != 0, Errors.ZERO_DIVISION); return a / b; } function divUp(uint256 a, uint256 b) internal pure returns (uint256) { _require(b != 0, Errors.ZERO_DIVISION); if (a == 0) { return 0; } else { return 1 + (a - 1) / b; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _HASHED_NAME = keccak256(bytes(name)); _HASHED_VERSION = keccak256(bytes(version)); _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view virtual returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, _getChainId(), address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash)); } function _getChainId() private view returns (uint256 chainId) { // Silence state mutability warning without generating bytecode. // See https://github.com/ethereum/solidity/issues/10090#issuecomment-741789128 and // https://github.com/ethereum/solidity/issues/2691 this; // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } } }
{ "optimizer": { "enabled": true, "runs": 800 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"normalizedWeights","type":"uint256[]"},{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"},{"internalType":"uint256","name":"pauseWindowDuration","type":"uint256"},{"internalType":"uint256","name":"bufferPeriodDuration","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"PausedStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"SwapFeePercentageChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"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":"getInvariant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastInvariant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNormalizedWeights","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPausedState","outputs":[{"internalType":"bool","name":"paused","type":"bool"},{"internalType":"uint256","name":"pauseWindowEndTime","type":"uint256"},{"internalType":"uint256","name":"bufferPeriodEndTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPoolId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSwapFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"uint256","name":"protocolSwapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"onExitPool","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"uint256","name":"protocolSwapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"onJoinPool","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IVault.SwapKind","name":"kind","type":"uint8"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"contract IERC20","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct IPoolSwapStructs.SwapRequest","name":"request","type":"tuple"},{"internalType":"uint256","name":"balanceTokenIn","type":"uint256"},{"internalType":"uint256","name":"balanceTokenOut","type":"uint256"}],"name":"onSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"uint256","name":"protocolSwapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"queryExit","outputs":[{"internalType":"uint256","name":"bptIn","type":"uint256"},{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"uint256","name":"protocolSwapFeePercentage","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"queryJoin","outputs":[{"internalType":"uint256","name":"bptOut","type":"uint256"},{"internalType":"uint256[]","name":"amountsIn","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"swapFeePercentage","type":"uint256"}],"name":"setSwapFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6105006040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9610120523480156200003757600080fd5b50604051620058b6380380620058b68339810160408190526200005a9162000cf2565b88888888878787878785516002146200007557600162000078565b60025b6040805180820190915260018152603160f81b6020808301918252336080526001600160601b0319606087901b1660a0528b51908c0190812060c0529151902060e0527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6101005289518a918a918a918a918a918a918a91849184918a918a9162000107916003919062000abb565b5080516200011d90600490602084019062000abb565b50620001359150506276a70083111561019462000865565b6200014962278d0082111561019562000865565b42909101610140819052016101605284516200016b906002111560c862000865565b6200018360088651111560c96200086560201b60201c565b62000199856200087a60201b62000d571760201c565b620001a48462000886565b6040516309b2760f60e01b81526000906001600160a01b038b16906309b2760f90620001d5908c9060040162000eab565b602060405180830381600087803b158015620001f057600080fd5b505af115801562000205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022b919062000cd9565b9050896001600160a01b03166366a9c7d2828889516001600160401b03811180156200025657600080fd5b5060405190808252806020026020018201604052801562000281578160200160208202803683370190505b506040518463ffffffff1660e01b8152600401620002a29392919062000e0f565b600060405180830381600087803b158015620002bd57600080fd5b505af1158015620002d2573d6000803e3d6000fd5b5050506001600160601b031960608c901b1661018052506101a081905285516101c0528551620003045760006200031b565b856000815181106200031257fe5b60200260200101515b60601b6001600160601b0319166101e05285516001106200033e57600062000355565b856001815181106200034c57fe5b60200260200101515b60601b6001600160601b031916610200528551600210620003785760006200038f565b856002815181106200038657fe5b60200260200101515b60601b6001600160601b031916610220528551600310620003b2576000620003c9565b85600381518110620003c057fe5b60200260200101515b60601b6001600160601b031916610240528551600410620003ec57600062000403565b85600481518110620003fa57fe5b60200260200101515b60601b6001600160601b031916610260528551600510620004265760006200043d565b856005815181106200043457fe5b60200260200101515b60601b6001600160601b0319166102805285516006106200046057600062000477565b856006815181106200046e57fe5b60200260200101515b60601b6001600160601b0319166102a05285516007106200049a576000620004b1565b85600781518110620004a857fe5b60200260200101515b60601b6001600160601b0319166102c0528551620004d1576000620004f7565b620004f786600081518110620004e357fe5b6020026020010151620008f560201b60201c565b6102e05285516001106200050d5760006200051f565b6200051f86600181518110620004e357fe5b6103005285516002106200053557600062000547565b6200054786600281518110620004e357fe5b6103205285516003106200055d5760006200056f565b6200056f86600381518110620004e357fe5b6103405285516004106200058557600062000597565b6200059786600481518110620004e357fe5b610360528551600510620005ad576000620005bf565b620005bf86600581518110620004e357fe5b610380528551600610620005d5576000620005e7565b620005e786600681518110620004e357fe5b6103a0528551600710620005fd5760006200060f565b6200060f86600781518110620004e357fe5b6103c08181525050505050505050505050505050505050505050600086519050620006478187516200099760201b62000d651760201c565b6000806000805b848160ff161015620006cd5760008a8260ff16815181106200066c57fe5b6020026020010151905062000694662386f26fc1000082101561012e6200086560201b60201c565b620006ae8186620009a660201b62000d721790919060201c565b945082811115620006c3578160ff1693508092505b506001016200064e565b50620006e6670de0b6b3a7640000841461013462000865565b6103e08290528851620006fb57600062000712565b886000815181106200070957fe5b60200260200101515b610400528851600110620007285760006200073f565b886001815181106200073657fe5b60200260200101515b610420528851600210620007555760006200076c565b886002815181106200076357fe5b60200260200101515b6104405288516003106200078257600062000799565b886003815181106200079057fe5b60200260200101515b610460528851600410620007af576000620007c6565b88600481518110620007bd57fe5b60200260200101515b610480528851600510620007dc576000620007f3565b88600581518110620007ea57fe5b60200260200101515b6104a05288516006106200080957600062000820565b886006815181106200081757fe5b60200260200101515b6104c0528851600710620008365760006200084d565b886007815181106200084457fe5b60200260200101515b6104e0525062000f329b505050505050505050505050565b8162000876576200087681620009c3565b5050565b80620008768162000a16565b6200089b64e8d4a5100082101560cb62000865565b620008b367016345785d8a000082111560ca62000865565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90620008ea90839062000ec0565b60405180910390a150565b600080826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200093257600080fd5b505afa15801562000947573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200096d919062000dec565b60ff16905060006200098c60128362000aa360201b62000d841760201c565b600a0a949350505050565b62000876828214606762000865565b6000828201620009ba848210158362000865565b90505b92915050565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60028151101562000a275762000aa0565b60008160008151811062000a3757fe5b602002602001015190506000600190505b825181101562000a9d57600083828151811062000a6157fe5b6020026020010151905062000a92816001600160a01b0316846001600160a01b03161060656200086560201b60201c565b915060010162000a48565b50505b50565b600062000ab583831115600162000865565b50900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1062000afe57805160ff191683800117855562000b2e565b8280016001018555821562000b2e579182015b8281111562000b2e57825182559160200191906001019062000b11565b5062000b3c92915062000b40565b5090565b5b8082111562000b3c576000815560010162000b41565b8051620009bd8162000f1c565b600082601f83011262000b75578081fd5b815162000b8c62000b868262000ef0565b62000ec9565b81815291506020808301908481018184028601820187101562000bae57600080fd5b60005b8481101562000bda57815162000bc78162000f1c565b8452928201929082019060010162000bb1565b505050505092915050565b600082601f83011262000bf6578081fd5b815162000c0762000b868262000ef0565b81815291506020808301908481018184028601820187101562000c2957600080fd5b60005b8481101562000bda5781518452928201929082019060010162000c2c565b600082601f83011262000c5b578081fd5b81516001600160401b0381111562000c71578182fd5b602062000c87601f8301601f1916820162000ec9565b9250818352848183860101111562000c9e57600080fd5b60005b8281101562000cbe57848101820151848201830152810162000ca1565b8281111562000cd05760008284860101525b50505092915050565b60006020828403121562000ceb578081fd5b5051919050565b60008060008060008060008060006101208a8c03121562000d11578485fd5b62000d1d8b8b62000b57565b60208b01519099506001600160401b038082111562000d3a578687fd5b62000d488d838e0162000c4a565b995060408c015191508082111562000d5e578687fd5b62000d6c8d838e0162000c4a565b985060608c015191508082111562000d82578687fd5b62000d908d838e0162000b64565b975060808c015191508082111562000da6578687fd5b5062000db58c828d0162000be5565b95505060a08a0151935060c08a0151925060e08a0151915062000ddd8b6101008c0162000b57565b90509295985092959850929598565b60006020828403121562000dfe578081fd5b815160ff81168114620009ba578182fd5b60006060820185835260206060818501528186518084526080860191508288019350845b8181101562000e5b5762000e48855162000f10565b8352938301939183019160010162000e33565b505084810360408601528551808252908201925081860190845b8181101562000e9d5762000e8a835162000f10565b8552938301939183019160010162000e75565b509298975050505050505050565b602081016003831062000eba57fe5b91905290565b90815260200190565b6040518181016001600160401b038111828210171562000ee857600080fd5b604052919050565b60006001600160401b0382111562000f06578081fd5b5060209081020190565b6001600160a01b031690565b6001600160a01b038116811462000aa057600080fd5b60805160a05160601c60c05160e051610100516101205161014051610160516101805160601c6101a0516101c0516101e05160601c6102005160601c6102205160601c6102405160601c6102605160601c6102805160601c6102a05160601c6102c05160601c6102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a0516104c0516104e05161476e6200114860003980611ec55280612857525080611e8252806127f6525080611e3f5280612795525080611dfc5280612734525080611db952806126d3525080611d765280612672525080611d335280612611525080611cf052806125b05250806122d0528061230452806123405250806116285280611b1e5250806115e55280611abd5250806115a25280611a5c52508061155f52806119fb52508061151c528061199a5250806114d9528061193952508061149652806118d85250806114455280611877525080611ae3528061281c525080611a8252806127bb525080611a21528061275a5250806119c052806126f952508061195f52806126985250806118fe528061263752508061189d52806125d652508061183c52806125755250806111025250806105d7525080610835525080610ef1525080610ecd525080610ab5525080610ff452508061103652508061101552508061081152508061079b525061476e6000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c80637ecebe001161010f578063a9059cbb116100a2578063d5c096c411610071578063d5c096c4146103e6578063d73dd623146103f9578063dd62ed3e1461040c578063f89f27ed1461041f576101f0565b8063a9059cbb146103b0578063aaabadc5146103c3578063c0ff1a15146103cb578063d505accf146103d3576101f0565b80638d928af8116100de5780638d928af81461038557806395d89b411461038d5780639b02cdde146103955780639d2c110c1461039d576101f0565b80637ecebe0014610337578063851c1bb31461034a57806387ec68171461035d578063893d20e814610370576101f0565b806338e9922e11610187578063661884631161015657806366188463146102e8578063679aefce146102fb57806370a082311461030357806374f3b00914610316576101f0565b806338e9922e146102a457806338fff2d0146102b757806355c67628146102bf5780636028bfd4146102c7576101f0565b80631c0de051116101c35780631c0de0511461025d57806323b872dd14610274578063313ce567146102875780633644e5151461029c576101f0565b806306fdde03146101f5578063095ea7b31461021357806316c38b3c1461023357806318160ddd14610248575b600080fd5b6101fd610434565b60405161020a9190614647565b60405180910390f35b61022661022136600461401c565b6104cb565b60405161020a919061457e565b610246610241366004614113565b6104e2565b005b6102506104f6565b60405161020a91906145a1565b6102656104fc565b60405161020a93929190614589565b610226610282366004613f67565b610525565b61028f6105a8565b60405161020a91906146b3565b6102506105ad565b6102466102b236600461449d565b6105bc565b6102506105d5565b6102506105f9565b6102da6102d536600461414b565b6105ff565b60405161020a92919061469a565b6102266102f636600461401c565b610636565b610250610690565b610250610311366004613f13565b6106bb565b61032961032436600461414b565b6106da565b60405161020a929190614559565b610250610345366004613f13565b61077c565b610250610358366004614248565b610797565b6102da61036b36600461414b565b6107e9565b61037861080f565b60405161020a9190614532565b610378610833565b6101fd610857565b6102506108b8565b6102506103ab3660046143a1565b6108be565b6102266103be36600461401c565b6109a5565b6103786109b2565b6102506109bc565b6102466103e1366004613fa7565b610a80565b6103296103f436600461414b565b610bc9565b61022661040736600461401c565b610cec565b61025061041a366004613f2f565b610d22565b610427610d4d565b60405161020a9190614546565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b820191906000526020600020905b8154815290600101906020018083116104a357829003601f168201915b505050505090505b90565b60006104d8338484610d9a565b5060015b92915050565b6104ea610e02565b6104f381610e30565b50565b60025490565b6000806000610509610eae565b159250610514610ecb565b915061051e610eef565b9050909192565b6001600160a01b0383166000818152600160209081526040808320338085529252822054919261056391148061055b5750838210155b610197610f13565b61056e858585610f21565b336001600160a01b0386161480159061058957506000198114155b1561059b5761059b8533858403610d9a565b60019150505b9392505050565b601290565b60006105b7610ff0565b905090565b6105c4610e02565b6105cc61108d565b6104f3816110a2565b7f000000000000000000000000000000000000000000000000000000000000000090565b60075490565b600060606106158651610610611100565b610d65565b61062a898989898989896111246111ec611252565b97509795505050505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106106725761066d33856000610d9a565b610686565b61068633856106818487610d84565b610d9a565b5060019392505050565b60006105b761069d6104f6565b6106b56106a86109bc565b6106b0611100565b611374565b90611398565b6001600160a01b0381166000908152602081905260409020545b919050565b606080886107046106e9610833565b6001600160a01b0316336001600160a01b03161460cd610f13565b61071961070f6105d5565b82146101f4610f13565b60606107236113e9565b905061072f8882611666565b60006060806107438e8e8e8e8e8e8e611124565b9250925092506107538d846116c7565b61075d82856111ec565b61076781856111ec565b909550935050505b5097509795505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016107cc9291906144ef565b604051602081830303815290604052805190602001209050919050565b600060606107fa8651610610611100565b61062a8989898989898961175a6117d7611252565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b60085490565b6000806108ce8560200151611838565b905060006108df8660400151611838565b90506000865160018111156108f057fe5b1415610956576109038660600151611b4d565b60608701526109128583611b71565b945061091e8482611b71565b935061092e866060015183611b71565b60608701526000610940878787611b7d565b905061094c8183611bb8565b93505050506105a1565b6109608583611b71565b945061096c8482611b71565b935061097c866060015182611b71565b6060870152600061098e878787611bc4565b905061099a8184611bf7565b905061094c81611c03565b60006104d8338484610f21565b60006105b7611c1a565b600060606109c8610833565b6001600160a01b031663f94d46686109de6105d5565b6040518263ffffffff1660e01b81526004016109fa91906145a1565b60006040518083038186803b158015610a1257600080fd5b505afa158015610a26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a4e9190810190614047565b50915050610a6381610a5e6113e9565b611666565b6060610a6d611c94565b9050610a798183611ef1565b9250505090565b610a8e8442111560d1610f13565b6001600160a01b0387166000908152600560209081526040808320549051909291610ae5917f0000000000000000000000000000000000000000000000000000000000000000918c918c918c9188918d91016145c9565b6040516020818303038152906040528051906020012090506000610b0882611f63565b9050600060018288888860405160008152602001604052604051610b2f9493929190614629565b6020604051602081039080840390855afa158015610b51573d6000803e3d6000fd5b5050604051601f1901519150610b9390506001600160a01b03821615801590610b8b57508b6001600160a01b0316826001600160a01b0316145b6101f8610f13565b6001600160a01b038b166000908152600560205260409020600185019055610bbc8b8b8b610d9a565b5050505050505050505050565b60608088610bd86106e9610833565b610be361070f6105d5565b6060610bed6113e9565b9050610bf76104f6565b610c9d5760006060610c0b8d8d8d8a611f7f565b91509150610c20620f424083101560cc610f13565b610c2e6000620f424061201a565b610c3d8b620f4240840361201a565b610c4781846117d7565b80610c50611100565b67ffffffffffffffff81118015610c6657600080fd5b50604051908082528060200260200182016040528015610c90578160200160208202803683370190505b509550955050505061076f565b610ca78882611666565b6000606080610cbb8e8e8e8e8e8e8e61175a565b925092509250610ccb8c8461201a565b610cd582856117d7565b610cdf81856111ec565b909550935061076f915050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916104d89185906106819086610d72565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606105b7611c94565b80610d61816120b0565b5050565b610d618183146067610f13565b60008282016105a18482101583610f13565b6000610d94838311156001610f13565b50900390565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610df59085906145a1565b60405180910390a3505050565b6000610e196000356001600160e01b031916610797565b90506104f3610e288233612129565b610191610f13565b8015610e5057610e4b610e41610ecb565b4210610193610f13565b610e65565b610e65610e5b610eef565b42106101a9610f13565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490610ea390839061457e565b60405180910390a150565b6000610eb8610eef565b4211806105b757505060065460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b81610d6157610d6181612219565b6001600160a01b038316600090815260208190526040902054610f4982821015610196610f13565b610f606001600160a01b0384161515610199610f13565b6001600160a01b03808516600090815260208190526040808220858503905591851681522054610f909083610d72565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610fe29086906145a1565b60405180910390a350505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061105d61226c565b306040516020016110729594939291906145fd565b60405160208183030381529060405280519060200120905090565b6110a0611098610eae565b610192610f13565b565b6110b564e8d4a5100082101560cb610f13565b6110cb67016345785d8a000082111560ca610f13565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90610ea39083906145a1565b7f000000000000000000000000000000000000000000000000000000000000000090565b60006060806060611133611c94565b905061113d610eae565b1561117457600061114e828a611ef1565b905061115f8983600854848b612270565b925061116e8984610d84612380565b506111c0565b61117c611100565b67ffffffffffffffff8111801561119257600080fd5b506040519080825280602002602001820160405280156111bc578160200160208202803683370190505b5091505b6111cb8882876123eb565b90945092506111db888483612458565b600855509750975097945050505050565b60005b6111f7611100565b81101561124d5761122e83828151811061120d57fe5b602002602001015183838151811061122157fe5b6020026020010151612471565b83828151811061123a57fe5b60209081029190910101526001016111ef565b505050565b333014611310576000306001600160a01b0316600036604051611276929190614507565b6000604051808303816000865af19150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5050905080600081146112c757fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146112f2573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b606061131a6113e9565b90506113268782611666565b6000606061133d8c8c8c8c8c8c8c8c63ffffffff16565b509150915061135081848663ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b60008282026105a184158061139157508385838161138e57fe5b04145b6003610f13565b60006113a78215156004610f13565b826113b4575060006104dc565b670de0b6b3a7640000838102906113d7908583816113ce57fe5b04146005610f13565b8281816113e057fe5b049150506104dc565b606060006113f5611100565b905060608167ffffffffffffffff8111801561141057600080fd5b5060405190808252806020026020018201604052801561143a578160200160208202803683370190505b5090508115611482577f00000000000000000000000000000000000000000000000000000000000000008160008151811061147157fe5b60200260200101818152505061148b565b91506104c89050565b6001821115611482577f0000000000000000000000000000000000000000000000000000000000000000816001815181106114c257fe5b6020026020010181815250506002821115611482577f00000000000000000000000000000000000000000000000000000000000000008160028151811061150557fe5b6020026020010181815250506003821115611482577f00000000000000000000000000000000000000000000000000000000000000008160038151811061154857fe5b6020026020010181815250506004821115611482577f00000000000000000000000000000000000000000000000000000000000000008160048151811061158b57fe5b6020026020010181815250506005821115611482577f0000000000000000000000000000000000000000000000000000000000000000816005815181106115ce57fe5b6020026020010181815250506006821115611482577f00000000000000000000000000000000000000000000000000000000000000008160068151811061161157fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b60200260200101818152505091505090565b60005b611671611100565b81101561124d576116a883828151811061168757fe5b602002602001015183838151811061169b57fe5b6020026020010151611374565b8382815181106116b457fe5b6020908102919091010152600101611669565b6001600160a01b0382166000908152602081905260409020546116ef82821015610196610f13565b6001600160a01b038316600090815260208190526040902082820390556002546117199083610d84565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610df59086906145a1565b600060608061176761108d565b6060611771611c94565b9050600061177f828a611ef1565b905060606117928a84600854858c612270565b90506117a18a82610d84612380565b600060606117b08c868b612491565b915091506117bf8c82876124eb565b600855909e909d50909b509950505050505050505050565b60005b6117e2611100565b81101561124d576118198382815181106117f857fe5b602002602001015183838151811061180c57fe5b60200260200101516124fa565b83828151811061182557fe5b60209081029190910101526001016117da565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561189b57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156118fc57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561195d57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156119be57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a1f57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a8057507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611ae157507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b6106d5610135612219565b600080611b656007548461252d90919063ffffffff16565b90506105a18382610d84565b60006105a18383611374565b6000611b8761108d565b611bb083611b988660200151612571565b84611ba68860400151612571565b886060015161287b565b949350505050565b60006105a18383612471565b6000611bce61108d565b611bb083611bdf8660200151612571565b84611bed8860400151612571565b88606001516128f6565b60006105a183836124fa565b60006104dc611c1360075461296c565b8390612992565b6000611c24610833565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5c57600080fd5b505afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b79190614270565b60606000611ca0611100565b905060608167ffffffffffffffff81118015611cbb57600080fd5b50604051908082528060200260200182016040528015611ce5578160200160208202803683370190505b5090508115611482577f000000000000000000000000000000000000000000000000000000000000000081600081518110611d1c57fe5b6020026020010181815250506001821115611482577f000000000000000000000000000000000000000000000000000000000000000081600181518110611d5f57fe5b6020026020010181815250506002821115611482577f000000000000000000000000000000000000000000000000000000000000000081600281518110611da257fe5b6020026020010181815250506003821115611482577f000000000000000000000000000000000000000000000000000000000000000081600381518110611de557fe5b6020026020010181815250506004821115611482577f000000000000000000000000000000000000000000000000000000000000000081600481518110611e2857fe5b6020026020010181815250506005821115611482577f000000000000000000000000000000000000000000000000000000000000000081600581518110611e6b57fe5b6020026020010181815250506006821115611482577f000000000000000000000000000000000000000000000000000000000000000081600681518110611eae57fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b670de0b6b3a764000060005b8351811015611f5357611f49611f42858381518110611f1857fe5b6020026020010151858481518110611f2c57fe5b60200260200101516129d490919063ffffffff16565b8390612a23565b9150600101611efd565b506104dc60008211610137610f13565b6000611f6d610ff0565b826040516020016107cc929190614517565b60006060611f8b61108d565b6000611f9684612a4f565b9050611fb16000826002811115611fa957fe5b1460ce610f13565b6060611fbc85612a65565b9050611fd0611fc9611100565b8251610d65565b611fdc81610a5e6113e9565b6060611fe6611c94565b90506000611ff48284611ef1565b90506000612004826106b0611100565b6008929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461203d9082610d72565b6001600160a01b0383166000908152602081905260409020556002546120639082610d72565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906120a49085906145a1565b60405180910390a35050565b6002815110156120bf576104f3565b6000816000815181106120ce57fe5b602002602001015190506000600190505b825181101561124d5760008382815181106120f657fe5b6020026020010151905061211f816001600160a01b0316846001600160a01b0316106065610f13565b91506001016120df565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b61214861080f565b6001600160a01b031614158015612163575061216383612a7b565b1561218b5761217061080f565b6001600160a01b0316336001600160a01b03161490506104dc565b612193611c1a565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b81526004016121c2939291906145aa565b60206040518083038186803b1580156121da57600080fd5b505afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612212919061412f565b90506104dc565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b4690565b60608061227b611100565b67ffffffffffffffff8111801561229157600080fd5b506040519080825280602002602001820160405280156122bb578160200160208202803683370190505b509050826122ca579050612377565b61233d877f0000000000000000000000000000000000000000000000000000000000000000815181106122f957fe5b6020026020010151877f00000000000000000000000000000000000000000000000000000000000000008151811061232d57fe5b6020026020010151878787612a95565b817f00000000000000000000000000000000000000000000000000000000000000008151811061236957fe5b602090810291909101015290505b95945050505050565b60005b61238b611100565b8110156123e5576123c68482815181106123a157fe5b60200260200101518483815181106123b557fe5b60200260200101518463ffffffff16565b8482815181106123d257fe5b6020908102919091010152600101612383565b50505050565b6000606060006123fa84612a4f565b9050600081600281111561240a57fe5b14156124255761241b868686612b0d565b9250925050612450565b600181600281111561243357fe5b14156124435761241b8685612beb565b61241b868686612c1d565b505b935093915050565b60006124678484610d84612380565b611bb08285611ef1565b60006124808215156004610f13565b81838161248957fe5b049392505050565b6000606060006124a084612a4f565b905060018160028111156124b057fe5b14156124c15761241b868686612c88565b60028160028111156124cf57fe5b14156124e05761241b868686612ce2565b61244e610136612219565b60006124678484610d72612380565b60006125098215156004610f13565b82612516575060006104dc565b81600184038161252257fe5b0460010190506104dc565b600082820261254784158061139157508385838161138e57fe5b806125565760009150506104dc565b670de0b6b3a764000060001982015b046001019150506104dc565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156125d457507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561263557507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561269657507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156126f757507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561275857507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156127b957507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561281a57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b600061289d61289287670429d069189e0000612a23565b831115610130610f13565b60006128a98784610d72565b905060006128b78883612992565b905060006128c58887611398565b905060006128d38383612d8a565b90506128e86128e18261296c565b8990612a23565b9a9950505050505050505050565b600061291861290d85670429d069189e0000612a23565b831115610131610f13565b600061292e6129278685610d84565b8690612992565b9050600061293c8588612992565b9050600061294a8383612d8a565b9050600061296082670de0b6b3a7640000610d84565b90506128e88a8261252d565b6000670de0b6b3a764000082106129845760006104dc565b50670de0b6b3a76400000390565b60006129a18215156004610f13565b826129ae575060006104dc565b670de0b6b3a7640000838102906129c8908583816113ce57fe5b82600182038161256557fe5b6000806129e18484612db6565b905060006129fb6129f48361271061252d565b6001610d72565b905080821015612a10576000925050506104dc565b612a1a8282610d84565b925050506104dc565b6000828202612a3d84158061139157508385838161138e57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906104dc919061428c565b6060818060200190518101906105a19190614352565b6000612a8d631c74c91760e11b610797565b909114919050565b6000838311612aa657506000612377565b6000612ab28585612992565b90506000612ac8670de0b6b3a764000088611398565b9050612adc826709b6e64a8ec60000612ec1565b91506000612aea8383612d8a565b90506000612b01612afa8361296c565b8b90612a23565b90506128e88187612a23565b60006060612b1961108d565b600080612b2585612ed8565b91509150612b3d612b34611100565b82106064610f13565b6060612b47611100565b67ffffffffffffffff81118015612b5d57600080fd5b50604051908082528060200260200182016040528015612b87578160200160208202803683370190505b509050612bc6888381518110612b9957fe5b6020026020010151888481518110612bad57fe5b602002602001015185612bbe6104f6565b600754612efa565b818381518110612bd257fe5b6020908102919091010152919791965090945050505050565b600060606000612bfa84612fb7565b90506060612c108683612c0b6104f6565b612fcd565b9196919550909350505050565b60006060612c2961108d565b60606000612c368561307f565b91509150612c478251610610611100565b612c5382610a5e6113e9565b6000612c6b888885612c636104f6565b600754613097565b9050612c7b8282111560cf610f13565b9791965090945050505050565b60006060806000612c988561307f565b91509150612cae612ca7611100565b8351610d65565b612cba82610a5e6113e9565b6000612cd2888885612cca6104f6565b6007546132bc565b9050612c7b8282101560d0610f13565b60006060600080612cf285612ed8565b91509150612d01612b34611100565b6060612d0b611100565b67ffffffffffffffff81118015612d2157600080fd5b50604051908082528060200260200182016040528015612d4b578160200160208202803683370190505b509050612bc6888381518110612d5d57fe5b6020026020010151888481518110612d7157fe5b602002602001015185612d826104f6565b6007546134cd565b600080612d978484612db6565b90506000612daa6129f48361271061252d565b90506123778282610d72565b600081612dcc5750670de0b6b3a76400006104dc565b82612dd9575060006104dc565b612dea600160ff1b84106006610f13565b82612e10770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007610f13565b826000670c7d713b49da000083138015612e315750670f43fc2c04ee000083125b15612e68576000612e418461356f565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612e76565b81612e7284613696565b0290505b670de0b6b3a76400009005612eae680238fd42c5cf03ffff198212801590612ea7575068070c1cc73b00c800008213155b6008610f13565b612eb781613a44565b9695505050505050565b600081831015612ed157816105a1565b5090919050565b60008082806020019051810190612eef919061431c565b909590945092505050565b600080612f1184612f0b8188610d84565b90612992565b9050612f2a6709b6e64a8ec60000821015610132610f13565b6000612f48612f41670de0b6b3a764000089611398565b8390612d8a565b90506000612f5f612f588361296c565b8a90612a23565b90506000612f6c8961296c565b90506000612f7a838361252d565b90506000612f888483610d84565b9050612fa7612fa0612f998a61296c565b8490612a23565b8290610d72565b9c9b505050505050505050505050565b6000818060200190518101906105a191906142ef565b60606000612fdb8484611398565b90506060855167ffffffffffffffff81118015612ff757600080fd5b50604051908082528060200260200182016040528015613021578160200160208202803683370190505b50905060005b8651811015613075576130568388838151811061304057fe5b6020026020010151612a2390919063ffffffff16565b82828151811061306257fe5b6020908102919091010152600101613027565b5095945050505050565b6060600082806020019051810190612eef91906142a8565b60006060845167ffffffffffffffff811180156130b357600080fd5b506040519080825280602002602001820160405280156130dd578160200160208202803683370190505b5090506000805b88518110156131a25761313d8982815181106130fc57fe5b6020026020010151612f0b89848151811061311357fe5b60200260200101518c858151811061312757fe5b6020026020010151610d8490919063ffffffff16565b83828151811061314957fe5b60200260200101818152505061319861319189838151811061316757fe5b602002602001015185848151811061317b57fe5b602002602001015161252d90919063ffffffff16565b8390610d72565b91506001016130e4565b50670de0b6b3a764000060005b895181101561329b5760008482815181106131c657fe5b602002602001015184111561321d5760006131ef6131e38661296c565b8d858151811061304057fe5b90506000613203828c868151811061312757fe5b9050613214613191611c138b61296c565b92505050613234565b88828151811061322957fe5b602002602001015190505b600061325d8c848151811061324557fe5b60200260200101516106b5848f878151811061312757fe5b905061328f6132888c858151811061327157fe5b6020026020010151836129d490919063ffffffff16565b8590612a23565b935050506001016131af565b506132af6132a88261296c565b879061252d565b9998505050505050505050565b60006060845167ffffffffffffffff811180156132d857600080fd5b50604051908082528060200260200182016040528015613302578160200160208202803683370190505b5090506000805b88518110156133aa5761336289828151811061332157fe5b60200260200101516106b589848151811061333857fe5b60200260200101518c858151811061334c57fe5b6020026020010151610d7290919063ffffffff16565b83828151811061336e57fe5b6020026020010181815250506133a061319189838151811061338c57fe5b602002602001015185848151811061304057fe5b9150600101613309565b50670de0b6b3a764000060005b895181101561348b576000838583815181106133cf57fe5b6020026020010151111561342b5760006133f46131e386670de0b6b3a7640000610d84565b90506000613408828c868151811061312757fe5b9050613422613191611f42670de0b6b3a76400008c610d84565b92505050613442565b88828151811061343757fe5b602002602001015190505b600061346b8c848151811061345357fe5b60200260200101516106b5848f878151811061334c57fe5b905061347f6132888c858151811061327157fe5b935050506001016133b7565b50670de0b6b3a764000081106134c1576134b76134b082670de0b6b3a7640000610d84565b8790612a23565b9350505050612377565b60009350505050612377565b6000806134de84612f0b8188610d72565b90506134f76729a2241af62c0000821115610133610f13565b600061350e612f41670de0b6b3a764000089612992565b9050600061352e61352783670de0b6b3a7640000610d84565b8a9061252d565b9050600061353b8961296c565b90506000613549838361252d565b905060006135578483610d84565b9050612fa7612fa06135688a61296c565b8490612992565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401906ec097ce7bc90715b34b9f0fffffffff19850102816135ab57fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f826002919005919091010295945050505050565b60006136a6600083136064610f13565b670de0b6b3a76400008212156136e1576136d7826ec097ce7bc90715b34b9f1000000000816136d157fe5b05613696565b60000390506106d5565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261373257770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261376a576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126137b2576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126137ed576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261382457693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261385b57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126138905768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126138bb57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126138f0576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312613925576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312613959576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac831261398d576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d6310000080860302816139b057fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000613a73680238fd42c5cf03ffff198312158015613a6c575068070c1cc73b00c800008313155b6009610f13565b6000821215613aa757613a8882600003613a44565b6ec097ce7bc90715b34b9f100000000081613a9f57fe5b0590506106d5565b60006806f05b59d3b20000008312613ae757506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613b1d565b6803782dace9d90000008312613b1957506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613b1d565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412613b6d5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613ba9576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412613be357682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613c1d576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412613c5657680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412613c8f5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613cc8576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613d015768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b80356104dc81614708565b600082601f830112613e3d578081fd5b8151613e50613e4b826146e8565b6146c1565b818152915060208083019084810181840286018201871015613e7157600080fd5b60005b84811015613e9057815184529282019290820190600101613e74565b505050505092915050565b600082601f830112613eab578081fd5b813567ffffffffffffffff811115613ec1578182fd5b613ed4601f8201601f19166020016146c1565b9150808252836020828501011115613eeb57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106104dc57600080fd5b600060208284031215613f24578081fd5b81356105a181614708565b60008060408385031215613f41578081fd5b8235613f4c81614708565b91506020830135613f5c81614708565b809150509250929050565b600080600060608486031215613f7b578081fd5b8335613f8681614708565b92506020840135613f9681614708565b929592945050506040919091013590565b600080600080600080600060e0888a031215613fc1578283fd5b8735613fcc81614708565b96506020880135613fdc81614708565b95506040880135945060608801359350608088013560ff81168114613fff578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561402e578182fd5b823561403981614708565b946020939093013593505050565b60008060006060848603121561405b578081fd5b835167ffffffffffffffff80821115614072578283fd5b818601915086601f830112614085578283fd5b8151614093613e4b826146e8565b80828252602080830192508086018b8283870289010111156140b3578788fd5b8796505b848710156140de5780516140ca81614708565b8452600196909601959281019281016140b7565b5089015190975093505050808211156140f5578283fd5b5061410286828701613e2d565b925050604084015190509250925092565b600060208284031215614124578081fd5b81356105a18161471d565b600060208284031215614140578081fd5b81516105a18161471d565b600080600080600080600060e0888a031215614165578081fd5b8735965060208089013561417881614708565b9650604089013561418881614708565b9550606089013567ffffffffffffffff808211156141a4578384fd5b818b0191508b601f8301126141b7578384fd5b81356141c5613e4b826146e8565b8082825285820191508585018f8788860288010111156141e3578788fd5b8795505b838610156142055780358352600195909501949186019186016141e7565b509850505060808b0135955060a08b0135945060c08b013592508083111561422b578384fd5b50506142398a828b01613e9b565b91505092959891949750929550565b600060208284031215614259578081fd5b81356001600160e01b0319811681146105a1578182fd5b600060208284031215614281578081fd5b81516105a181614708565b60006020828403121561429d578081fd5b81516105a18161472b565b6000806000606084860312156142bc578081fd5b83516142c78161472b565b602085015190935067ffffffffffffffff8111156142e3578182fd5b61410286828701613e2d565b60008060408385031215614301578182fd5b825161430c8161472b565b6020939093015192949293505050565b600080600060608486031215614330578081fd5b835161433b8161472b565b602085015160409095015190969495509392505050565b60008060408385031215614364578182fd5b825161436f8161472b565b602084015190925067ffffffffffffffff81111561438b578182fd5b61439785828601613e2d565b9150509250929050565b6000806000606084860312156143b5578081fd5b833567ffffffffffffffff808211156143cc578283fd5b81860191506101208083890312156143e2578384fd5b6143eb816146c1565b90506143f78884613f04565b81526144068860208501613e22565b60208201526144188860408501613e22565b6040820152606083013560608201526080830135608082015260a083013560a08201526144488860c08501613e22565b60c082015261445a8860e08501613e22565b60e08201526101008084013583811115614472578586fd5b61447e8a828701613e9b565b9183019190915250976020870135975060409096013595945050505050565b6000602082840312156144ae578081fd5b5035919050565b6000815180845260208085019450808401835b838110156144e4578151875295820195908201906001016144c8565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6000602082526105a160208301846144b5565b60006040825261456c60408301856144b5565b828103602084015261237781856144b5565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b8181101561467357858101830151858201604001528201614657565b818111156146845783604083870101525b50601f01601f1916929092016040019392505050565b600083825260406020830152611bb060408301846144b5565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146e057600080fd5b604052919050565b600067ffffffffffffffff8211156146fe578081fd5b5060209081020190565b6001600160a01b03811681146104f357600080fd5b80151581146104f357600080fd5b600381106104f357600080fdfea2646970667358221220a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb464736f6c63430007010033000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000008e1bc9bf0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b000000000000000000000000000000000000000000000000000000000000001842616c616e636572203830204e45584f20323020574554480000000000000000000000000000000000000000000000000000000000000000000000000000000f422d38304e45584f2d32305745544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d815206000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000b1a2bc2ec50000000000000000000000000000000000000000000000000000002c68af0bb140000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f05760003560e01c80637ecebe001161010f578063a9059cbb116100a2578063d5c096c411610071578063d5c096c4146103e6578063d73dd623146103f9578063dd62ed3e1461040c578063f89f27ed1461041f576101f0565b8063a9059cbb146103b0578063aaabadc5146103c3578063c0ff1a15146103cb578063d505accf146103d3576101f0565b80638d928af8116100de5780638d928af81461038557806395d89b411461038d5780639b02cdde146103955780639d2c110c1461039d576101f0565b80637ecebe0014610337578063851c1bb31461034a57806387ec68171461035d578063893d20e814610370576101f0565b806338e9922e11610187578063661884631161015657806366188463146102e8578063679aefce146102fb57806370a082311461030357806374f3b00914610316576101f0565b806338e9922e146102a457806338fff2d0146102b757806355c67628146102bf5780636028bfd4146102c7576101f0565b80631c0de051116101c35780631c0de0511461025d57806323b872dd14610274578063313ce567146102875780633644e5151461029c576101f0565b806306fdde03146101f5578063095ea7b31461021357806316c38b3c1461023357806318160ddd14610248575b600080fd5b6101fd610434565b60405161020a9190614647565b60405180910390f35b61022661022136600461401c565b6104cb565b60405161020a919061457e565b610246610241366004614113565b6104e2565b005b6102506104f6565b60405161020a91906145a1565b6102656104fc565b60405161020a93929190614589565b610226610282366004613f67565b610525565b61028f6105a8565b60405161020a91906146b3565b6102506105ad565b6102466102b236600461449d565b6105bc565b6102506105d5565b6102506105f9565b6102da6102d536600461414b565b6105ff565b60405161020a92919061469a565b6102266102f636600461401c565b610636565b610250610690565b610250610311366004613f13565b6106bb565b61032961032436600461414b565b6106da565b60405161020a929190614559565b610250610345366004613f13565b61077c565b610250610358366004614248565b610797565b6102da61036b36600461414b565b6107e9565b61037861080f565b60405161020a9190614532565b610378610833565b6101fd610857565b6102506108b8565b6102506103ab3660046143a1565b6108be565b6102266103be36600461401c565b6109a5565b6103786109b2565b6102506109bc565b6102466103e1366004613fa7565b610a80565b6103296103f436600461414b565b610bc9565b61022661040736600461401c565b610cec565b61025061041a366004613f2f565b610d22565b610427610d4d565b60405161020a9190614546565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b820191906000526020600020905b8154815290600101906020018083116104a357829003601f168201915b505050505090505b90565b60006104d8338484610d9a565b5060015b92915050565b6104ea610e02565b6104f381610e30565b50565b60025490565b6000806000610509610eae565b159250610514610ecb565b915061051e610eef565b9050909192565b6001600160a01b0383166000818152600160209081526040808320338085529252822054919261056391148061055b5750838210155b610197610f13565b61056e858585610f21565b336001600160a01b0386161480159061058957506000198114155b1561059b5761059b8533858403610d9a565b60019150505b9392505050565b601290565b60006105b7610ff0565b905090565b6105c4610e02565b6105cc61108d565b6104f3816110a2565b7f5e6989c0e2b6600ab585d56bf05479d5450a60c80002000000000000000000c190565b60075490565b600060606106158651610610611100565b610d65565b61062a898989898989896111246111ec611252565b97509795505050505050565b3360009081526001602090815260408083206001600160a01b03861684529091528120548083106106725761066d33856000610d9a565b610686565b61068633856106818487610d84565b610d9a565b5060019392505050565b60006105b761069d6104f6565b6106b56106a86109bc565b6106b0611100565b611374565b90611398565b6001600160a01b0381166000908152602081905260409020545b919050565b606080886107046106e9610833565b6001600160a01b0316336001600160a01b03161460cd610f13565b61071961070f6105d5565b82146101f4610f13565b60606107236113e9565b905061072f8882611666565b60006060806107438e8e8e8e8e8e8e611124565b9250925092506107538d846116c7565b61075d82856111ec565b61076781856111ec565b909550935050505b5097509795505050505050565b6001600160a01b031660009081526005602052604090205490565b60007f0000000000000000000000008e9aa87e45e92bad84d5f8dd1bff34fb92637de9826040516020016107cc9291906144ef565b604051602081830303815290604052805190602001209050919050565b600060606107fa8651610610611100565b61062a8989898989898961175a6117d7611252565b7f000000000000000000000000ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b90565b7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c890565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104c05780601f10610495576101008083540402835291602001916104c0565b60085490565b6000806108ce8560200151611838565b905060006108df8660400151611838565b90506000865160018111156108f057fe5b1415610956576109038660600151611b4d565b60608701526109128583611b71565b945061091e8482611b71565b935061092e866060015183611b71565b60608701526000610940878787611b7d565b905061094c8183611bb8565b93505050506105a1565b6109608583611b71565b945061096c8482611b71565b935061097c866060015182611b71565b6060870152600061098e878787611bc4565b905061099a8184611bf7565b905061094c81611c03565b60006104d8338484610f21565b60006105b7611c1a565b600060606109c8610833565b6001600160a01b031663f94d46686109de6105d5565b6040518263ffffffff1660e01b81526004016109fa91906145a1565b60006040518083038186803b158015610a1257600080fd5b505afa158015610a26573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a4e9190810190614047565b50915050610a6381610a5e6113e9565b611666565b6060610a6d611c94565b9050610a798183611ef1565b9250505090565b610a8e8442111560d1610f13565b6001600160a01b0387166000908152600560209081526040808320549051909291610ae5917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918c918c918c9188918d91016145c9565b6040516020818303038152906040528051906020012090506000610b0882611f63565b9050600060018288888860405160008152602001604052604051610b2f9493929190614629565b6020604051602081039080840390855afa158015610b51573d6000803e3d6000fd5b5050604051601f1901519150610b9390506001600160a01b03821615801590610b8b57508b6001600160a01b0316826001600160a01b0316145b6101f8610f13565b6001600160a01b038b166000908152600560205260409020600185019055610bbc8b8b8b610d9a565b5050505050505050505050565b60608088610bd86106e9610833565b610be361070f6105d5565b6060610bed6113e9565b9050610bf76104f6565b610c9d5760006060610c0b8d8d8d8a611f7f565b91509150610c20620f424083101560cc610f13565b610c2e6000620f424061201a565b610c3d8b620f4240840361201a565b610c4781846117d7565b80610c50611100565b67ffffffffffffffff81118015610c6657600080fd5b50604051908082528060200260200182016040528015610c90578160200160208202803683370190505b509550955050505061076f565b610ca78882611666565b6000606080610cbb8e8e8e8e8e8e8e61175a565b925092509250610ccb8c8461201a565b610cd582856117d7565b610cdf81856111ec565b909550935061076f915050565b3360008181526001602090815260408083206001600160a01b038716845290915281205490916104d89185906106819086610d72565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60606105b7611c94565b80610d61816120b0565b5050565b610d618183146067610f13565b60008282016105a18482101583610f13565b6000610d94838311156001610f13565b50900390565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610df59085906145a1565b60405180910390a3505050565b6000610e196000356001600160e01b031916610797565b90506104f3610e288233612129565b610191610f13565b8015610e5057610e4b610e41610ecb565b4210610193610f13565b610e65565b610e65610e5b610eef565b42106101a9610f13565b6006805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490610ea390839061457e565b60405180910390a150565b6000610eb8610eef565b4211806105b757505060065460ff161590565b7f00000000000000000000000000000000000000000000000000000000618e837790565b7f00000000000000000000000000000000000000000000000000000000618e837790565b81610d6157610d6181612219565b6001600160a01b038316600090815260208190526040902054610f4982821015610196610f13565b610f606001600160a01b0384161515610199610f13565b6001600160a01b03808516600090815260208190526040808220858503905591851681522054610f909083610d72565b6001600160a01b0380851660008181526020819052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610fe29086906145a1565b60405180910390a350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f516abaf988b0082897f6ee6dd944146e869b7f71f4599a113bfacb97c5ca1c867fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc661105d61226c565b306040516020016110729594939291906145fd565b60405160208183030381529060405280519060200120905090565b6110a0611098610eae565b610192610f13565b565b6110b564e8d4a5100082101560cb610f13565b6110cb67016345785d8a000082111560ca610f13565b60078190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc90610ea39083906145a1565b7f000000000000000000000000000000000000000000000000000000000000000290565b60006060806060611133611c94565b905061113d610eae565b1561117457600061114e828a611ef1565b905061115f8983600854848b612270565b925061116e8984610d84612380565b506111c0565b61117c611100565b67ffffffffffffffff8111801561119257600080fd5b506040519080825280602002602001820160405280156111bc578160200160208202803683370190505b5091505b6111cb8882876123eb565b90945092506111db888483612458565b600855509750975097945050505050565b60005b6111f7611100565b81101561124d5761122e83828151811061120d57fe5b602002602001015183838151811061122157fe5b6020026020010151612471565b83828151811061123a57fe5b60209081029190910101526001016111ef565b505050565b333014611310576000306001600160a01b0316600036604051611276929190614507565b6000604051808303816000865af19150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5050905080600081146112c757fe5b60046000803e6000516001600160e01b0319166343adbafb60e01b81146112f2573d6000803e3d6000fd5b506020600460003e604060205260243d03602460403e601c3d016000f35b606061131a6113e9565b90506113268782611666565b6000606061133d8c8c8c8c8c8c8c8c63ffffffff16565b509150915061135081848663ffffffff16565b8051601f1982018390526343adbafb603f1983015260200260231982016044820181fd5b60008282026105a184158061139157508385838161138e57fe5b04145b6003610f13565b60006113a78215156004610f13565b826113b4575060006104dc565b670de0b6b3a7640000838102906113d7908583816113ce57fe5b04146005610f13565b8281816113e057fe5b049150506104dc565b606060006113f5611100565b905060608167ffffffffffffffff8111801561141057600080fd5b5060405190808252806020026020018201604052801561143a578160200160208202803683370190505b5090508115611482577f00000000000000000000000000000000000000000000000000000000000000018160008151811061147157fe5b60200260200101818152505061148b565b91506104c89050565b6001821115611482577f0000000000000000000000000000000000000000000000000000000000000001816001815181106114c257fe5b6020026020010181815250506002821115611482577f00000000000000000000000000000000000000000000000000000000000000008160028151811061150557fe5b6020026020010181815250506003821115611482577f00000000000000000000000000000000000000000000000000000000000000008160038151811061154857fe5b6020026020010181815250506004821115611482577f00000000000000000000000000000000000000000000000000000000000000008160048151811061158b57fe5b6020026020010181815250506005821115611482577f0000000000000000000000000000000000000000000000000000000000000000816005815181106115ce57fe5b6020026020010181815250506006821115611482577f00000000000000000000000000000000000000000000000000000000000000008160068151811061161157fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b60200260200101818152505091505090565b60005b611671611100565b81101561124d576116a883828151811061168757fe5b602002602001015183838151811061169b57fe5b6020026020010151611374565b8382815181106116b457fe5b6020908102919091010152600101611669565b6001600160a01b0382166000908152602081905260409020546116ef82821015610196610f13565b6001600160a01b038316600090815260208190526040902082820390556002546117199083610d84565b6002556040516000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610df59086906145a1565b600060608061176761108d565b6060611771611c94565b9050600061177f828a611ef1565b905060606117928a84600854858c612270565b90506117a18a82610d84612380565b600060606117b08c868b612491565b915091506117bf8c82876124eb565b600855909e909d50909b509950505050505050505050565b60005b6117e2611100565b81101561124d576118198382815181106117f857fe5b602002602001015183838151811061180c57fe5b60200260200101516124fa565b83828151811061182557fe5b60209081029190910101526001016117da565b60007f000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d8152066001600160a01b0316826001600160a01b0316141561189b57507f00000000000000000000000000000000000000000000000000000000000000016106d5565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316826001600160a01b031614156118fc57507f00000000000000000000000000000000000000000000000000000000000000016106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561195d57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156119be57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a1f57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611a8057507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611ae157507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b6106d5610135612219565b600080611b656007548461252d90919063ffffffff16565b90506105a18382610d84565b60006105a18383611374565b6000611b8761108d565b611bb083611b988660200151612571565b84611ba68860400151612571565b886060015161287b565b949350505050565b60006105a18383612471565b6000611bce61108d565b611bb083611bdf8660200151612571565b84611bed8860400151612571565b88606001516128f6565b60006105a183836124fa565b60006104dc611c1360075461296c565b8390612992565b6000611c24610833565b6001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b158015611c5c57600080fd5b505afa158015611c70573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b79190614270565b60606000611ca0611100565b905060608167ffffffffffffffff81118015611cbb57600080fd5b50604051908082528060200260200182016040528015611ce5578160200160208202803683370190505b5090508115611482577f0000000000000000000000000000000000000000000000000b1a2bc2ec50000081600081518110611d1c57fe5b6020026020010181815250506001821115611482577f00000000000000000000000000000000000000000000000002c68af0bb14000081600181518110611d5f57fe5b6020026020010181815250506002821115611482577f000000000000000000000000000000000000000000000000000000000000000081600281518110611da257fe5b6020026020010181815250506003821115611482577f000000000000000000000000000000000000000000000000000000000000000081600381518110611de557fe5b6020026020010181815250506004821115611482577f000000000000000000000000000000000000000000000000000000000000000081600481518110611e2857fe5b6020026020010181815250506005821115611482577f000000000000000000000000000000000000000000000000000000000000000081600581518110611e6b57fe5b6020026020010181815250506006821115611482577f000000000000000000000000000000000000000000000000000000000000000081600681518110611eae57fe5b6020026020010181815250506007821115611482577f00000000000000000000000000000000000000000000000000000000000000008160078151811061165457fe5b670de0b6b3a764000060005b8351811015611f5357611f49611f42858381518110611f1857fe5b6020026020010151858481518110611f2c57fe5b60200260200101516129d490919063ffffffff16565b8390612a23565b9150600101611efd565b506104dc60008211610137610f13565b6000611f6d610ff0565b826040516020016107cc929190614517565b60006060611f8b61108d565b6000611f9684612a4f565b9050611fb16000826002811115611fa957fe5b1460ce610f13565b6060611fbc85612a65565b9050611fd0611fc9611100565b8251610d65565b611fdc81610a5e6113e9565b6060611fe6611c94565b90506000611ff48284611ef1565b90506000612004826106b0611100565b6008929092555099919850909650505050505050565b6001600160a01b03821660009081526020819052604090205461203d9082610d72565b6001600160a01b0383166000908152602081905260409020556002546120639082610d72565b6002556040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906120a49085906145a1565b60405180910390a35050565b6002815110156120bf576104f3565b6000816000815181106120ce57fe5b602002602001015190506000600190505b825181101561124d5760008382815181106120f657fe5b6020026020010151905061211f816001600160a01b0316846001600160a01b0316106065610f13565b91506001016120df565b600073ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b61214861080f565b6001600160a01b031614158015612163575061216383612a7b565b1561218b5761217061080f565b6001600160a01b0316336001600160a01b03161490506104dc565b612193611c1a565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b81526004016121c2939291906145aa565b60206040518083038186803b1580156121da57600080fd5b505afa1580156121ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612212919061412f565b90506104dc565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b4690565b60608061227b611100565b67ffffffffffffffff8111801561229157600080fd5b506040519080825280602002602001820160405280156122bb578160200160208202803683370190505b509050826122ca579050612377565b61233d877f0000000000000000000000000000000000000000000000000000000000000000815181106122f957fe5b6020026020010151877f00000000000000000000000000000000000000000000000000000000000000008151811061232d57fe5b6020026020010151878787612a95565b817f00000000000000000000000000000000000000000000000000000000000000008151811061236957fe5b602090810291909101015290505b95945050505050565b60005b61238b611100565b8110156123e5576123c68482815181106123a157fe5b60200260200101518483815181106123b557fe5b60200260200101518463ffffffff16565b8482815181106123d257fe5b6020908102919091010152600101612383565b50505050565b6000606060006123fa84612a4f565b9050600081600281111561240a57fe5b14156124255761241b868686612b0d565b9250925050612450565b600181600281111561243357fe5b14156124435761241b8685612beb565b61241b868686612c1d565b505b935093915050565b60006124678484610d84612380565b611bb08285611ef1565b60006124808215156004610f13565b81838161248957fe5b049392505050565b6000606060006124a084612a4f565b905060018160028111156124b057fe5b14156124c15761241b868686612c88565b60028160028111156124cf57fe5b14156124e05761241b868686612ce2565b61244e610136612219565b60006124678484610d72612380565b60006125098215156004610f13565b82612516575060006104dc565b81600184038161252257fe5b0460010190506104dc565b600082820261254784158061139157508385838161138e57fe5b806125565760009150506104dc565b670de0b6b3a764000060001982015b046001019150506104dc565b60007f000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d8152066001600160a01b0316826001600160a01b031614156125d457507f0000000000000000000000000000000000000000000000000b1a2bc2ec5000006106d5565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316826001600160a01b0316141561263557507f00000000000000000000000000000000000000000000000002c68af0bb1400006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561269657507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156126f757507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561275857507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156127b957507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316141561281a57507f00000000000000000000000000000000000000000000000000000000000000006106d5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415611b4257507f00000000000000000000000000000000000000000000000000000000000000006106d5565b600061289d61289287670429d069189e0000612a23565b831115610130610f13565b60006128a98784610d72565b905060006128b78883612992565b905060006128c58887611398565b905060006128d38383612d8a565b90506128e86128e18261296c565b8990612a23565b9a9950505050505050505050565b600061291861290d85670429d069189e0000612a23565b831115610131610f13565b600061292e6129278685610d84565b8690612992565b9050600061293c8588612992565b9050600061294a8383612d8a565b9050600061296082670de0b6b3a7640000610d84565b90506128e88a8261252d565b6000670de0b6b3a764000082106129845760006104dc565b50670de0b6b3a76400000390565b60006129a18215156004610f13565b826129ae575060006104dc565b670de0b6b3a7640000838102906129c8908583816113ce57fe5b82600182038161256557fe5b6000806129e18484612db6565b905060006129fb6129f48361271061252d565b6001610d72565b905080821015612a10576000925050506104dc565b612a1a8282610d84565b925050506104dc565b6000828202612a3d84158061139157508385838161138e57fe5b670de0b6b3a764000090049392505050565b6000818060200190518101906104dc919061428c565b6060818060200190518101906105a19190614352565b6000612a8d631c74c91760e11b610797565b909114919050565b6000838311612aa657506000612377565b6000612ab28585612992565b90506000612ac8670de0b6b3a764000088611398565b9050612adc826709b6e64a8ec60000612ec1565b91506000612aea8383612d8a565b90506000612b01612afa8361296c565b8b90612a23565b90506128e88187612a23565b60006060612b1961108d565b600080612b2585612ed8565b91509150612b3d612b34611100565b82106064610f13565b6060612b47611100565b67ffffffffffffffff81118015612b5d57600080fd5b50604051908082528060200260200182016040528015612b87578160200160208202803683370190505b509050612bc6888381518110612b9957fe5b6020026020010151888481518110612bad57fe5b602002602001015185612bbe6104f6565b600754612efa565b818381518110612bd257fe5b6020908102919091010152919791965090945050505050565b600060606000612bfa84612fb7565b90506060612c108683612c0b6104f6565b612fcd565b9196919550909350505050565b60006060612c2961108d565b60606000612c368561307f565b91509150612c478251610610611100565b612c5382610a5e6113e9565b6000612c6b888885612c636104f6565b600754613097565b9050612c7b8282111560cf610f13565b9791965090945050505050565b60006060806000612c988561307f565b91509150612cae612ca7611100565b8351610d65565b612cba82610a5e6113e9565b6000612cd2888885612cca6104f6565b6007546132bc565b9050612c7b8282101560d0610f13565b60006060600080612cf285612ed8565b91509150612d01612b34611100565b6060612d0b611100565b67ffffffffffffffff81118015612d2157600080fd5b50604051908082528060200260200182016040528015612d4b578160200160208202803683370190505b509050612bc6888381518110612d5d57fe5b6020026020010151888481518110612d7157fe5b602002602001015185612d826104f6565b6007546134cd565b600080612d978484612db6565b90506000612daa6129f48361271061252d565b90506123778282610d72565b600081612dcc5750670de0b6b3a76400006104dc565b82612dd9575060006104dc565b612dea600160ff1b84106006610f13565b82612e10770bce5086492111aea88f4bb1ca6bcf584181ea8059f7653284106007610f13565b826000670c7d713b49da000083138015612e315750670f43fc2c04ee000083125b15612e68576000612e418461356f565b9050670de0b6b3a764000080820784020583670de0b6b3a764000083050201915050612e76565b81612e7284613696565b0290505b670de0b6b3a76400009005612eae680238fd42c5cf03ffff198212801590612ea7575068070c1cc73b00c800008213155b6008610f13565b612eb781613a44565b9695505050505050565b600081831015612ed157816105a1565b5090919050565b60008082806020019051810190612eef919061431c565b909590945092505050565b600080612f1184612f0b8188610d84565b90612992565b9050612f2a6709b6e64a8ec60000821015610132610f13565b6000612f48612f41670de0b6b3a764000089611398565b8390612d8a565b90506000612f5f612f588361296c565b8a90612a23565b90506000612f6c8961296c565b90506000612f7a838361252d565b90506000612f888483610d84565b9050612fa7612fa0612f998a61296c565b8490612a23565b8290610d72565b9c9b505050505050505050505050565b6000818060200190518101906105a191906142ef565b60606000612fdb8484611398565b90506060855167ffffffffffffffff81118015612ff757600080fd5b50604051908082528060200260200182016040528015613021578160200160208202803683370190505b50905060005b8651811015613075576130568388838151811061304057fe5b6020026020010151612a2390919063ffffffff16565b82828151811061306257fe5b6020908102919091010152600101613027565b5095945050505050565b6060600082806020019051810190612eef91906142a8565b60006060845167ffffffffffffffff811180156130b357600080fd5b506040519080825280602002602001820160405280156130dd578160200160208202803683370190505b5090506000805b88518110156131a25761313d8982815181106130fc57fe5b6020026020010151612f0b89848151811061311357fe5b60200260200101518c858151811061312757fe5b6020026020010151610d8490919063ffffffff16565b83828151811061314957fe5b60200260200101818152505061319861319189838151811061316757fe5b602002602001015185848151811061317b57fe5b602002602001015161252d90919063ffffffff16565b8390610d72565b91506001016130e4565b50670de0b6b3a764000060005b895181101561329b5760008482815181106131c657fe5b602002602001015184111561321d5760006131ef6131e38661296c565b8d858151811061304057fe5b90506000613203828c868151811061312757fe5b9050613214613191611c138b61296c565b92505050613234565b88828151811061322957fe5b602002602001015190505b600061325d8c848151811061324557fe5b60200260200101516106b5848f878151811061312757fe5b905061328f6132888c858151811061327157fe5b6020026020010151836129d490919063ffffffff16565b8590612a23565b935050506001016131af565b506132af6132a88261296c565b879061252d565b9998505050505050505050565b60006060845167ffffffffffffffff811180156132d857600080fd5b50604051908082528060200260200182016040528015613302578160200160208202803683370190505b5090506000805b88518110156133aa5761336289828151811061332157fe5b60200260200101516106b589848151811061333857fe5b60200260200101518c858151811061334c57fe5b6020026020010151610d7290919063ffffffff16565b83828151811061336e57fe5b6020026020010181815250506133a061319189838151811061338c57fe5b602002602001015185848151811061304057fe5b9150600101613309565b50670de0b6b3a764000060005b895181101561348b576000838583815181106133cf57fe5b6020026020010151111561342b5760006133f46131e386670de0b6b3a7640000610d84565b90506000613408828c868151811061312757fe5b9050613422613191611f42670de0b6b3a76400008c610d84565b92505050613442565b88828151811061343757fe5b602002602001015190505b600061346b8c848151811061345357fe5b60200260200101516106b5848f878151811061334c57fe5b905061347f6132888c858151811061327157fe5b935050506001016133b7565b50670de0b6b3a764000081106134c1576134b76134b082670de0b6b3a7640000610d84565b8790612a23565b9350505050612377565b60009350505050612377565b6000806134de84612f0b8188610d72565b90506134f76729a2241af62c0000821115610133610f13565b600061350e612f41670de0b6b3a764000089612992565b9050600061352e61352783670de0b6b3a7640000610d84565b8a9061252d565b9050600061353b8961296c565b90506000613549838361252d565b905060006135578483610d84565b9050612fa7612fa06135688a61296c565b8490612992565b670de0b6b3a7640000026000806ec097ce7bc90715b34b9f1000000000808401906ec097ce7bc90715b34b9f0fffffffff19850102816135ab57fe5b05905060006ec097ce7bc90715b34b9f100000000082800205905081806ec097ce7bc90715b34b9f100000000081840205915060038205016ec097ce7bc90715b34b9f100000000082840205915060058205016ec097ce7bc90715b34b9f100000000082840205915060078205016ec097ce7bc90715b34b9f100000000082840205915060098205016ec097ce7bc90715b34b9f1000000000828402059150600b8205016ec097ce7bc90715b34b9f1000000000828402059150600d8205016ec097ce7bc90715b34b9f1000000000828402059150600f826002919005919091010295945050505050565b60006136a6600083136064610f13565b670de0b6b3a76400008212156136e1576136d7826ec097ce7bc90715b34b9f1000000000816136d157fe5b05613696565b60000390506106d5565b60007e1600ef3172e58d2e933ec884fde10064c63b5372d805e203c0000000000000831261373257770195e54c5dd42177f53a27172fa9ec630262827000000000830592506806f05b59d3b2000000015b73011798004d755d3c8bc8e03204cf44619e000000831261376a576b1425982cf597cd205cef7380830592506803782dace9d9000000015b606492830292026e01855144814a7ff805980ff008400083126137b2576e01855144814a7ff805980ff008400068056bc75e2d63100000840205925068ad78ebc5ac62000000015b6b02df0ab5a80a22c61ab5a70083126137ed576b02df0ab5a80a22c61ab5a70068056bc75e2d6310000084020592506856bc75e2d631000000015b693f1fce3da636ea5cf850831261382457693f1fce3da636ea5cf85068056bc75e2d631000008402059250682b5e3af16b18800000015b690127fa27722cc06cc5e2831261385b57690127fa27722cc06cc5e268056bc75e2d6310000084020592506815af1d78b58c400000015b68280e60114edb805d0383126138905768280e60114edb805d0368056bc75e2d631000008402059250680ad78ebc5ac6200000015b680ebc5fb4174612111083126138bb57680ebc5fb4174612111068056bc75e2d631000009384020592015b6808f00f760a4b2db55d83126138f0576808f00f760a4b2db55d68056bc75e2d6310000084020592506802b5e3af16b1880000015b6806f5f17757889379378312613925576806f5f177578893793768056bc75e2d63100000840205925068015af1d78b58c40000015b6806248f33704b2866038312613959576806248f33704b28660368056bc75e2d63100000840205925067ad78ebc5ac620000015b6805c548670b9510e7ac831261398d576805c548670b9510e7ac68056bc75e2d6310000084020592506756bc75e2d6310000015b600068056bc75e2d63100000840168056bc75e2d6310000080860302816139b057fe5b059050600068056bc75e2d63100000828002059050818068056bc75e2d63100000818402059150600382050168056bc75e2d63100000828402059150600582050168056bc75e2d63100000828402059150600782050168056bc75e2d63100000828402059150600982050168056bc75e2d63100000828402059150600b820501600202606485820105979650505050505050565b6000613a73680238fd42c5cf03ffff198312158015613a6c575068070c1cc73b00c800008313155b6009610f13565b6000821215613aa757613a8882600003613a44565b6ec097ce7bc90715b34b9f100000000081613a9f57fe5b0590506106d5565b60006806f05b59d3b20000008312613ae757506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613b1d565b6803782dace9d90000008312613b1957506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613b1d565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac620000008412613b6d5768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d6310000008412613ba9576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b188000008412613be357682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613c1d576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac62000008412613c5657680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d631000008412613c8f5768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613cc8576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613d015768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b80356104dc81614708565b600082601f830112613e3d578081fd5b8151613e50613e4b826146e8565b6146c1565b818152915060208083019084810181840286018201871015613e7157600080fd5b60005b84811015613e9057815184529282019290820190600101613e74565b505050505092915050565b600082601f830112613eab578081fd5b813567ffffffffffffffff811115613ec1578182fd5b613ed4601f8201601f19166020016146c1565b9150808252836020828501011115613eeb57600080fd5b8060208401602084013760009082016020015292915050565b8035600281106104dc57600080fd5b600060208284031215613f24578081fd5b81356105a181614708565b60008060408385031215613f41578081fd5b8235613f4c81614708565b91506020830135613f5c81614708565b809150509250929050565b600080600060608486031215613f7b578081fd5b8335613f8681614708565b92506020840135613f9681614708565b929592945050506040919091013590565b600080600080600080600060e0888a031215613fc1578283fd5b8735613fcc81614708565b96506020880135613fdc81614708565b95506040880135945060608801359350608088013560ff81168114613fff578384fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561402e578182fd5b823561403981614708565b946020939093013593505050565b60008060006060848603121561405b578081fd5b835167ffffffffffffffff80821115614072578283fd5b818601915086601f830112614085578283fd5b8151614093613e4b826146e8565b80828252602080830192508086018b8283870289010111156140b3578788fd5b8796505b848710156140de5780516140ca81614708565b8452600196909601959281019281016140b7565b5089015190975093505050808211156140f5578283fd5b5061410286828701613e2d565b925050604084015190509250925092565b600060208284031215614124578081fd5b81356105a18161471d565b600060208284031215614140578081fd5b81516105a18161471d565b600080600080600080600060e0888a031215614165578081fd5b8735965060208089013561417881614708565b9650604089013561418881614708565b9550606089013567ffffffffffffffff808211156141a4578384fd5b818b0191508b601f8301126141b7578384fd5b81356141c5613e4b826146e8565b8082825285820191508585018f8788860288010111156141e3578788fd5b8795505b838610156142055780358352600195909501949186019186016141e7565b509850505060808b0135955060a08b0135945060c08b013592508083111561422b578384fd5b50506142398a828b01613e9b565b91505092959891949750929550565b600060208284031215614259578081fd5b81356001600160e01b0319811681146105a1578182fd5b600060208284031215614281578081fd5b81516105a181614708565b60006020828403121561429d578081fd5b81516105a18161472b565b6000806000606084860312156142bc578081fd5b83516142c78161472b565b602085015190935067ffffffffffffffff8111156142e3578182fd5b61410286828701613e2d565b60008060408385031215614301578182fd5b825161430c8161472b565b6020939093015192949293505050565b600080600060608486031215614330578081fd5b835161433b8161472b565b602085015160409095015190969495509392505050565b60008060408385031215614364578182fd5b825161436f8161472b565b602084015190925067ffffffffffffffff81111561438b578182fd5b61439785828601613e2d565b9150509250929050565b6000806000606084860312156143b5578081fd5b833567ffffffffffffffff808211156143cc578283fd5b81860191506101208083890312156143e2578384fd5b6143eb816146c1565b90506143f78884613f04565b81526144068860208501613e22565b60208201526144188860408501613e22565b6040820152606083013560608201526080830135608082015260a083013560a08201526144488860c08501613e22565b60c082015261445a8860e08501613e22565b60e08201526101008084013583811115614472578586fd5b61447e8a828701613e9b565b9183019190915250976020870135975060409096013595945050505050565b6000602082840312156144ae578081fd5b5035919050565b6000815180845260208085019450808401835b838110156144e4578151875295820195908201906001016144c8565b509495945050505050565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6000602082526105a160208301846144b5565b60006040825261456c60408301856144b5565b828103602084015261237781856144b5565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b8181101561467357858101830151858201604001528201614657565b818111156146845783604083870101525b50601f01601f1916929092016040019392505050565b600083825260406020830152611bb060408301846144b5565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156146e057600080fd5b604052919050565b600067ffffffffffffffff8211156146fe578081fd5b5060209081020190565b6001600160a01b03811681146104f357600080fd5b80151581146104f357600080fd5b600381106104f357600080fdfea2646970667358221220a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb464736f6c63430007010033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c80000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000008e1bc9bf0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b000000000000000000000000000000000000000000000000000000000000001842616c616e636572203830204e45584f20323020574554480000000000000000000000000000000000000000000000000000000000000000000000000000000f422d38304e45584f2d32305745544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d815206000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000b1a2bc2ec50000000000000000000000000000000000000000000000000000002c68af0bb140000
-----Decoded View---------------
Arg [0] : vault (address): 0xBA12222222228d8Ba445958a75a0704d566BF2C8
Arg [1] : name (string): Balancer 80 NEXO 20 WETH
Arg [2] : symbol (string): B-80NEXO-20WETH
Arg [3] : tokens (address[]): 0xB62132e35a6c13ee1EE0f84dC5d40bad8d815206,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [4] : normalizedWeights (uint256[]): 800000000000000000,200000000000000000
Arg [5] : swapFeePercentage (uint256): 2500000000000000
Arg [6] : pauseWindowDuration (uint256): 0
Arg [7] : bufferPeriodDuration (uint256): 0
Arg [8] : owner (address): 0xBA1BA1ba1BA1bA1bA1Ba1BA1ba1BA1bA1ba1ba1B
-----Encoded View---------------
19 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [5] : 0000000000000000000000000000000000000000000000000008e1bc9bf04000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 000000000000000000000000ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1ba1b
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [10] : 42616c616e636572203830204e45584f20323020574554480000000000000000
Arg [11] : 000000000000000000000000000000000000000000000000000000000000000f
Arg [12] : 422d38304e45584f2d3230574554480000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [14] : 000000000000000000000000b62132e35a6c13ee1ee0f84dc5d40bad8d815206
Arg [15] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [17] : 0000000000000000000000000000000000000000000000000b1a2bc2ec500000
Arg [18] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Deployed Bytecode Sourcemap
1242:21086:24:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4957:81:17;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2582:164;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;8600:89:19:-;;;;;;:::i;:::-;;:::i;:::-;;5222:98:17;;;:::i;:::-;;;;;;;:::i;3154:363:6:-;;;:::i;:::-;;;;;;;;;:::i;3511:649:17:-;;;;;;:::i;:::-;;:::i;5135:81::-;;;:::i;:::-;;;;;;;:::i;5495:113::-;;;:::i;7999:158:19:-;;;;;;:::i;:::-;;:::i;7641:82::-;;;:::i;7830:106::-;;;:::i;14422:904::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;2959:379:17:-;;;;;;:::i;:::-;;:::i;22099:227:24:-;;;:::i;2458:118:17:-;;;;;;:::i;:::-;;:::i;11073:1171:19:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;5326:110:17:-;;;;;;:::i;:::-;;:::i;2487:430:0:-;;;;;;:::i;:::-;;:::i;12897:902:19:-;;;;;;:::i;:::-;;:::i;1715:80:20:-;;;:::i;:::-;;;;;;;:::i;7556:79:19:-;;;:::i;5044:85:17:-;;;:::i;6446:98:24:-;;;:::i;1817:1781:18:-;;;;;;:::i;:::-;;:::i;3344:161:17:-;;;;;;:::i;:::-;;:::i;1801:101:20:-;;;:::i;6622:461:24:-;;;:::i;4166:760:17:-;;;;;;:::i;:::-;;:::i;8923:2144:19:-;;;;;;:::i;:::-;;:::i;2752:201:17:-;;;;;;:::i;:::-;;:::i;2310:142::-;;;;;;:::i;:::-;;:::i;7089:117:24:-;;;:::i;:::-;;;;;;;:::i;4957:81:17:-;5026:5;5019:12;;;;;;;;;;;;;-1:-1:-1;;5019:12:17;;;;;;;;;;;;;;;;;;;;;;;;;;4994:13;;5019:12;;5026:5;;5019:12;;;5026:5;5019:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4957:81;;:::o;2582:164::-;2659:4;2675:42;2689:10;2701:7;2710:6;2675:13;:42::i;:::-;-1:-1:-1;2735:4:17;2582:164;;;;;:::o;8600:89:19:-;2156:21:0;:19;:21::i;:::-;8664:18:19::1;8675:6;8664:10;:18::i;:::-;8600:89:::0;:::o;5222:98:17:-;5301:12;;5222:98;:::o;3154:363:6:-;3257:11;3282:26;3322:27;3384:14;:12;:14::i;:::-;3383:15;3374:24;;3429;:22;:24::i;:::-;3408:45;;3485:25;:23;:25::i;:::-;3463:47;;3154:363;;;:::o;3511:649:17:-;-1:-1:-1;;;;;3684:18:17;;3641:4;3684:18;;;-1:-1:-1;3684:18:17;;;;;;;;3703:10;3684:30;;;;;;;;3641:4;;3724:91;;3733:20;;:50;;;3777:6;3757:16;:26;;3733:50;6726:3:1;3724:8:17;:91::i;:::-;3826:32;3832:6;3840:9;3851:6;3826:5;:32::i;:::-;-1:-1:-1;;;;;3873:20:17;;:10;:20;;;;:55;;-1:-1:-1;;;3897:31:17;;;3873:55;3869:263;;;4061:60;4075:6;4083:10;4114:6;4095:16;:25;4061:13;:60::i;:::-;4149:4;4142:11;;;3511:649;;;;;;:::o;5135:81::-;1610:2;5135:81;:::o;5495:113::-;5555:7;5581:20;:18;:20::i;:::-;5574:27;;5495:113;:::o;7999:158:19:-;2156:21:0;:19;:21::i;:::-;2970:18:6::1;:16;:18::i;:::-;8110:40:19::2;8132:17;8110:21;:40::i;7641:82::-:0;7709:7;7641:82;:::o;7830:106::-;7911:18;;7830:106;:::o;14422:904::-;14682:13;14697:27;14736:71;14772:8;:15;14789:17;:15;:17::i;:::-;14736:35;:71::i;:::-;14818:255;14844:6;14864;14884:9;14907:8;14929:15;14958:25;14997:8;15019:11;15044:19;14818:12;:255::i;:::-;14422:904;;;;;;;;;;:::o;2959:379:17:-;3090:10;3036:4;3079:22;;;:10;:22;;;;;;;;-1:-1:-1;;;;;3079:31:17;;;;;;;;;;3125:26;;;3121:189;;3167:37;3181:10;3193:7;3202:1;3167:13;:37::i;:::-;3121:189;;;3235:64;3249:10;3261:7;3270:28;:16;3291:6;3270:20;:28::i;:::-;3235:13;:64::i;:::-;-1:-1:-1;3327:4:17;;2959:379;-1:-1:-1;;;2959:379:17:o;22099:227:24:-;22139:7;22253:66;22305:13;:11;:13::i;:::-;22253:43;22262:14;:12;:14::i;:::-;22278:17;:15;:17::i;:::-;22253:8;:43::i;:::-;:51;;:66::i;2458:118:17:-;-1:-1:-1;;;;;2552:17:17;;2526:7;2552:17;;;;;;;;;;;2458:118;;;;:::o;11073:1171:19:-;11369:16;11387;11352:6;8766:68;8797:10;:8;:10::i;:::-;-1:-1:-1;;;;;8775:33:19;:10;:33;5392:3:1;8766:8:19;:68::i;:::-;8844:55;8863:11;:9;:11::i;:::-;8853:6;:21;7978:3:1;8844:8:19;:55::i;:::-;11415:31:::1;11449:17;:15;:17::i;:::-;11415:51;;11476:39;11490:8;11500:14;11476:13;:39::i;:::-;11527:19;11548:27;11577:38:::0;11619:196:::1;11644:6;11664;11684:9;11707:8;11729:15;11758:25;11797:8;11619:11;:196::i;:::-;11526:289;;;;;;11921:36;11937:6;11945:11;11921:15;:36::i;:::-;12069:47;12089:10;12101:14;12069:19;:47::i;:::-;12126:58;12146:21;12169:14;12126:19;:58::i;:::-;12203:10:::0;;-1:-1:-1;12215:21:19;-1:-1:-1;;;8909:1:19::1;11073:1171:::0;;;;;;;;;;;:::o;5326:110:17:-;-1:-1:-1;;;;;5415:14:17;5389:7;5415:14;;;:7;:14;;;;;;;5326:110::o;2487:430:0:-;2555:7;2876:22;2900:8;2859:50;;;;;;;;;:::i;:::-;;;;;;;;;;;;;2849:61;;;;;;2842:68;;2487:430;;;:::o;12897:902:19:-;13157:14;13173:26;13211:71;13247:8;:15;13264:17;:15;:17::i;13211:71::-;13293:253;13319:6;13339;13359:9;13382:8;13404:15;13433:25;13472:8;13494:11;13519:17;13293:12;:253::i;1715:80:20:-;1782:6;1715:80;:::o;7556:79:19:-;7622:6;7556:79;:::o;5044:85:17:-;5115:7;5108:14;;;;;;;;;;;;;-1:-1:-1;;5108:14:17;;;;;;;;;;;;;;;;;;;;;;;;;;5083:13;;5108:14;;5115:7;;5108:14;;;5115:7;5108:14;;;;;;;;;;;;;;;;;;;;;;;;6446:98:24;6523:14;;6446:98;:::o;1817:1781:18:-;1980:7;1999:28;2030:31;2045:7;:15;;;2030:14;:31::i;:::-;1999:62;;2071:29;2103:32;2118:7;:16;;;2103:14;:32::i;:::-;2071:64;-1:-1:-1;2166:24:18;2150:12;;:40;;;;;;;;;2146:1446;;;2335:38;2358:7;:14;;;2335:22;:38::i;:::-;2318:14;;;:55;2452:46;2461:14;2477:20;2452:8;:46::i;:::-;2435:63;;2530:48;2539:15;2556:21;2530:8;:48::i;:::-;2512:66;;2609:46;2618:7;:14;;;2634:20;2609:8;:46::i;:::-;2592:14;;;:63;2670:17;2690:56;2592:7;2714:14;2730:15;2690:14;:56::i;:::-;2670:76;;2840:48;2855:9;2866:21;2840:14;:48::i;:::-;2833:55;;;;;;;2146:1446;2983:46;2992:14;3008:20;2983:8;:46::i;:::-;2966:63;;3061:48;3070:15;3087:21;3061:8;:48::i;:::-;3043:66;;3140:47;3149:7;:14;;;3165:21;3140:8;:47::i;:::-;3123:14;;;:64;3202:16;3221:57;3123:7;3246:14;3262:15;3221;:57::i;:::-;3202:76;;3374:44;3387:8;3397:20;3374:12;:44::i;:::-;3363:55;;3554:27;3572:8;3554:17;:27::i;3344:161:17:-;3424:4;3440:36;3446:10;3458:9;3469:6;3440:5;:36::i;1801:101:20:-;1849:11;1879:16;:14;:16::i;6622:461:24:-;6667:7;6689:25;6720:10;:8;:10::i;:::-;-1:-1:-1;;;;;6720:24:24;;6745:11;:9;:11::i;:::-;6720:37;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6720:37:24;;;;;;;;;;;;:::i;:::-;6686:71;;;;6888:42;6902:8;6912:17;:15;:17::i;:::-;6888:13;:42::i;:::-;6941:34;6978:20;:18;:20::i;:::-;6941:57;;7015:61;7048:17;7067:8;7015:32;:61::i;:::-;7008:68;;;;6622:461;:::o;4166:760:17:-;4428:60;4456:8;4437:15;:27;;5606:3:1;4428:8:17;:60::i;:::-;-1:-1:-1;;;;;4515:14:17;;4499:13;4515:14;;;:7;:14;;;;;;;;;4571:69;;4515:14;;4499:13;4571:69;;4582:17;;4515:14;;4608:7;;4617:5;;4515:14;;4631:8;;4571:69;;:::i;:::-;;;;;;;;;;;;;4561:80;;;;;;4540:101;;4652:12;4667:28;4684:10;4667:16;:28::i;:::-;4652:43;;4706:14;4723:24;4733:4;4739:1;4742;4745;4723:24;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4723:24:17;;-1:-1:-1;;4723:24:17;;;-1:-1:-1;4757:79:17;;-1:-1:-1;;;;;;4767:20:17;;;;;;4766:43;;-1:-1:-1;;;;;;4793:15:17;;;;;;;4766:43;8211:3:1;4757:8:17;:79::i;:::-;-1:-1:-1;;;;;4847:14:17;;;;;;:7;:14;;;;;-1:-1:-1;4864:9:17;;4847:26;;4883:36;4847:14;4904:7;4913:5;4883:13;:36::i;:::-;4166:760;;;;;;;;;;;:::o;8923:2144:19:-;9219:16;9237;9202:6;8766:68;8797:10;:8;:10::i;8766:68::-;8844:55;8863:11;:9;:11::i;8844:55::-;9265:31:::1;9299:17;:15;:17::i;:::-;9265:51;;9331:13;:11;:13::i;:::-;9327:1734;;9366:20;9388:26;9418:54;9436:6;9444;9452:9;9463:8;9418:17;:54::i;:::-;9365:107;;;;9767:58;2763:3;9776:12;:28;;5338:3:1;9767:8:19;:58::i;:::-;9839:41;9863:1;2763:3;9839:15;:41::i;:::-;9894:55;9910:9;2763:3;9921:12;:27;9894:15;:55::i;:::-;10036:44;10054:9;10065:14;10036:17;:44::i;:::-;10103:9;10128:17;:15;:17::i;:::-;10114:32;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;10114:32:19::1;;10095:52;;;;;;;;;9327:1734;10178:39;10192:8;10202:14;10178:13;:39::i;:::-;10232:20;10254:26;10282:38:::0;10324:228:::1;10353:6;10377;10401:9;10428:8;10454:15;10487:25;10530:8;10324:11;:228::i;:::-;10231:321;;;;;;10666:40;10682:9;10693:12;10666:15;:40::i;:::-;10793:44;10811:9;10822:14;10793:17;:44::i;:::-;10936:58;10956:21;10979:14;10936:19;:58::i;:::-;11017:9:::0;;-1:-1:-1;11028:21:19;-1:-1:-1;11009:41:19::1;::::0;-1:-1:-1;;11009:41:19::1;2752:201:17::0;2859:10;2829:4;2880:22;;;:10;:22;;;;;;;;-1:-1:-1;;;;;2880:31:17;;;;;;;;;;2829:4;;2845:79;;2880:31;;:43;;2916:6;2880:35;:43::i;2310:142::-;-1:-1:-1;;;;;2419:17:17;;;2393:7;2419:17;;;-1:-1:-1;2419:17:17;;;;;;;;:26;;;;;;;;;;;;;2310:142::o;7089:117:24:-;7144:16;7179:20;:18;:20::i;1460:274:5:-;1670:5;1694:33;1670:5;1694:19;:33::i;:::-;1460:274;;:::o;855:131::-;933:46;947:1;942;:6;5002:3:1;933:8:5;:46::i;1157:239:7:-;1215:7;1319:5;;;1334:37;1343:6;;;;1215:7;1334:8;:37::i;948:166:9:-;1006:7;1025:37;1039:1;1034;:6;;4370:1:1;1025:8:9;:37::i;:::-;-1:-1:-1;1084:5:9;;;948:166::o;6895:208:17:-;-1:-1:-1;;;;;7014:17:17;;;;;;;-1:-1:-1;7014:17:17;;;;;;;;:26;;;;;;;;;;;;;;:35;;;7064:32;;;;;7014:35;;7064:32;:::i;:::-;;;;;;;;6895:208;;;:::o;2300:181:0:-;2355:16;2374:20;-1:-1:-1;;;;;;2386:7:0;;;2374:11;:20::i;:::-;2355:39;;2404:70;2413:33;2425:8;2435:10;2413:11;:33::i;:::-;6379:3:1;2404:8:0;:70::i;3793:358:6:-;3849:6;3845:232;;;3871:81;3898:24;:22;:24::i;:::-;3880:15;:42;6481:3:1;3871:8:6;:81::i;:::-;3845:232;;;3983:83;4010:25;:23;:25::i;:::-;3992:15;:43;7911:3:1;3983:8:6;:83::i;:::-;4087:7;:16;;-1:-1:-1;;4087:16:6;;;;;;;4118:26;;;;;;4087:16;;4118:26;:::i;:::-;;;;;;;;3793:358;:::o;4544:237::-;4591:4;4737:25;:23;:25::i;:::-;4719:15;:43;:55;;;-1:-1:-1;;4767:7:6;;;;4766:8;;4544:237::o;4894:108::-;4976:19;4894:108;:::o;5008:110::-;5091:20;5008:110;:::o;866:101:1:-;935:9;930:34;;946:18;954:9;946:7;:18::i;6245:618:17:-;-1:-1:-1;;;;;6385:16:17;;6360:22;6385:16;;;;;;;;;;;6411:63;6420:24;;;;6666:3:1;6411:8:17;:63::i;:::-;6617:72;-1:-1:-1;;;;;6626:23:17;;;;6864:3:1;6617:8:17;:72::i;:::-;-1:-1:-1;;;;;6700:16:17;;;:8;:16;;;;;;;;;;;6719:23;;;6700:42;;6774:19;;;;;;;:31;;6719:23;6774;:31::i;:::-;-1:-1:-1;;;;;6752:19:17;;;:8;:19;;;;;;;;;;;;:53;;;;6821:35;;;;;;;;;;6849:6;;6821:35;:::i;:::-;;;;;;;;6245:618;;;;:::o;2386:188:10:-;2447:7;2494:10;2506:12;2520:15;2537:13;:11;:13::i;:::-;2560:4;2483:83;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;2473:94;;;;;;2466:101;;2386:188;:::o;4220:98:6:-;4272:39;4281:14;:12;:14::i;:::-;6423:3:1;4272:8:6;:39::i;:::-;4220:98::o;8163:374:19:-;8239:87;2632:4;8248:17;:45;;5289:3:1;8239:8:19;:87::i;:::-;8336;2705:4;8345:17;:45;;5228:3:1;8336:8:19;:87::i;:::-;8434:18;:38;;;8487:43;;;;;;8455:17;;8487:43;:::i;7729:95::-;7805:12;7729:95;:::o;13702:2159:24:-;13986:19;14019:27;14060:38;14278:34;14315:20;:18;:20::i;:::-;14278:57;;14350:14;:12;:14::i;:::-;14346:1100;;;14686:27;14716:61;14749:17;14768:8;14716:32;:61::i;:::-;14686:91;;14815:212;14858:8;14884:17;14919:14;;14951:19;14988:25;14815;:212::i;:::-;14791:236;;15121:63;15136:8;15146:21;15169:14;15121;:63::i;:::-;14346:1100;;;;15417:17;:15;:17::i;:::-;15403:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;15403:32:24;;15379:56;;14346:1100;15484:46;15492:8;15502:17;15521:8;15484:7;:46::i;:::-;15456:74;;-1:-1:-1;15456:74:24;-1:-1:-1;15728:60:24;15748:8;15456:74;15770:17;15728:19;:60::i;:::-;15711:14;:77;-1:-1:-1;13702:2159:24;;;;;;;;;;;:::o;24023:247:19:-;24140:9;24135:129;24159:17;:15;:17::i;:::-;24155:1;:21;24135:129;;;24210:43;24223:7;24231:1;24223:10;;;;;;;;;;;;;;24235:14;24250:1;24235:17;;;;;;;;;;;;;;24210:12;:43::i;:::-;24197:7;24205:1;24197:10;;;;;;;;;;;;;;;;;:56;24178:3;;24135:129;;;;24023:247;;:::o;25538:6835::-;26219:10;26241:4;26219:27;26215:6152;;26533:28;;26515:12;;26541:4;;26533:28;;26515:12;;26552:8;;26533:28;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26514:47;;;26779:7;26812:1;26807:3336;;;;30303:9;26807:3336;27283:4;27280:1;27277;27262:26;27336:1;27330:8;-1:-1:-1;;;;;;27326:81:19;-1:-1:-1;;;27558:77:19;;27552:2;;27691:16;27688:1;27685;27670:38;27747:16;27744:1;27737:27;27552:2;;29158;29152:4;29149:1;29134:27;29355:2;29349:4;29342:16;29779:2;29761:16;29757:25;29751:4;29745;29730:53;30117:2;30099:16;30095:25;30092:1;30085:36;26645:3703;30378:31;30412:17;:15;:17::i;:::-;30378:51;;30443:39;30457:8;30467:14;30443:13;:39::i;:::-;30498:17;30517:29;30552:224;30577:6;30601;30625:9;30652:8;30678:15;30711:25;30754:8;30552:7;:224;;:::i;:::-;30497:279;;;;;30791:45;30807:12;30821:14;30791:15;:45;;:::i;:::-;31317:19;;-1:-1:-1;;31704:23:19;;31744:24;;;31990:66;-1:-1:-1;;31972:16:19;;31965:92;-1:-1:-1;31313:28:19;-1:-1:-1;;32083:16:19;;32339:2;32329:13;;32083:16;32315:28;1793:180:9;1851:7;1882:5;;;1897:51;1906:6;;;:20;;;1925:1;1920;1916;:5;;;;;;:10;1906:20;4467:1:1;1897:8:9;:51::i;2485:355:7:-;2547:7;2566:38;2575:6;;;4516:1:1;2566:8:7;:38::i;:::-;2619:6;2615:219;;-1:-1:-1;2648:1:7;2641:8;;2615:219;893:4;2700:7;;;;2721:51;;2700:1;:7;:1;2730:13;;;;;:20;4564:1:1;2721:8:7;:51::i;:::-;2822:1;2810:9;:13;;;;;;2803:20;;;;;21656:1122:19;21706:16;21734:19;21756:17;:15;:17::i;:::-;21734:39;;21783:31;21831:11;21817:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;21817:26:19;-1:-1:-1;21783:60:19;-1:-1:-1;21899:15:19;;21895:93;;21938:15;21918:14;21933:1;21918:17;;;;;;;;;;;;;:35;;;;;21895:93;;;21971:14;-1:-1:-1;21964:21:19;;-1:-1:-1;21964:21:19;21895:93;22019:1;22005:11;:15;22001:93;;;22044:15;22024:14;22039:1;22024:17;;;;;;;;;;;;;:35;;;;;22125:1;22111:11;:15;22107:93;;;22150:15;22130:14;22145:1;22130:17;;;;;;;;;;;;;:35;;;;;22231:1;22217:11;:15;22213:93;;;22256:15;22236:14;22251:1;22236:17;;;;;;;;;;;;;:35;;;;;22337:1;22323:11;:15;22319:93;;;22362:15;22342:14;22357:1;22342:17;;;;;;;;;;;;;:35;;;;;22443:1;22429:11;:15;22425:93;;;22468:15;22448:14;22463:1;22448:17;;;;;;;;;;;;;:35;;;;;22549:1;22535:11;:15;22531:93;;;22574:15;22554:14;22569:1;22554:17;;;;;;;;;;;;;:35;;;;;22655:1;22641:11;:15;22637:93;;;22680:15;22660:14;22675:1;22660:17;;;;;;;;;;;;;:35;;;;;22757:14;-1:-1:-1;;21656:1122:19;:::o;23253:237::-;23364:9;23359:125;23383:17;:15;:17::i;:::-;23379:1;:21;23359:125;;;23434:39;23443:7;23451:1;23443:10;;;;;;;;;;;;;;23455:14;23470:1;23455:17;;;;;;;;;;;;;;23434:8;:39::i;:::-;23421:7;23429:1;23421:10;;;;;;;;;;;;;;;;;:52;23402:3;;23359:125;;5889:350:17;-1:-1:-1;;;;;5990:16:17;;5965:22;5990:16;;;;;;;;;;;6016:63;6025:24;;;;6666:3:1;6016:8:17;:63::i;:::-;-1:-1:-1;;;;;6090:16:17;;:8;:16;;;;;;;;;;6109:23;;;6090:42;;6157:12;;:24;;6109:23;6157:16;:24::i;:::-;6142:12;:39;6196:36;;6221:1;;-1:-1:-1;;;;;6196:36:17;;;;;;;6225:6;;6196:36;:::i;9695:1744:24:-;10001:7;10022:16;10052;2970:18:6;:16;:18::i;:::-;10158:34:24::1;10195:20;:18;:20::i;:::-;10158:57;;10513:27;10543:61;10576:17;10595:8;10543:32;:61::i;:::-;10513:91;;10615:38;10656:188;10695:8;10717:17;10748:14;;10776:19;10809:25;10656;:188::i;:::-;10615:229;;10930:63;10945:8;10955:21;10978:14;10930;:63::i;:::-;11004:20;11026:26;11056:46;11064:8;11074:17;11093:8;11056:7;:46::i;:::-;11003:99;;;;11307:59;11327:8;11337:9;11348:17;11307:19;:59::i;:::-;11290:14;:76:::0;11385:12;;;;-1:-1:-1;11410:21:24;;-1:-1:-1;9695:1744:24;-1:-1:-1;;;;;;;;;;9695:1744:24:o;24795:243:19:-;24910:9;24905:127;24929:17;:15;:17::i;:::-;24925:1;:21;24905:127;;;24980:41;24991:7;24999:1;24991:10;;;;;;;;;;;;;;25003:14;25018:1;25003:17;;;;;;;;;;;;;;24980:10;:41::i;:::-;24967:7;24975:1;24967:10;;;;;;;;;;;;;;;;;:54;24948:3;;24905:127;;20783:671;20844:7;20903;-1:-1:-1;;;;;20894:16:19;;;;;;;20890:558;;;-1:-1:-1;20921:15:19;20914:22;;20890:558;20966:7;-1:-1:-1;;;;;20957:16:19;;;;;;;20953:495;;;-1:-1:-1;20984:15:19;20977:22;;20953:495;21029:7;-1:-1:-1;;;;;21020:16:19;;;;;;;21016:432;;;-1:-1:-1;21047:15:19;21040:22;;21016:432;21092:7;-1:-1:-1;;;;;21083:16:19;;;;;;;21079:369;;;-1:-1:-1;21110:15:19;21103:22;;21079:369;21155:7;-1:-1:-1;;;;;21146:16:19;;;;;;;21142:306;;;-1:-1:-1;21173:15:19;21166:22;;21142:306;21218:7;-1:-1:-1;;;;;21209:16:19;;;;;;;21205:243;;;-1:-1:-1;21236:15:19;21229:22;;21205:243;21281:7;-1:-1:-1;;;;;21272:16:19;;;;;;;21268:180;;;-1:-1:-1;21299:15:19;21292:22;;21268:180;21344:7;-1:-1:-1;;;;;21335:16:19;;;;;;;21331:117;;;-1:-1:-1;21362:15:19;21355:22;;21331:117;21408:29;6154:3:1;21408:7:19;:29::i;19765:279::-;19836:7;19947:17;19967:32;19980:18;;19967:6;:12;;:32;;;;:::i;:::-;19947:52;-1:-1:-1;20016:21:19;:6;19947:52;20016:10;:21::i;22940:144::-;23020:7;23046:31;23055:6;23063:13;23046:8;:31::i;7252:579:24:-;7455:7;2970:18:6;:16;:18::i;:::-;7554:270:24::1;7600:21;7639:38;7657:11;:19;;;7639:17;:38::i;:::-;7695:22;7735:39;7753:11;:20;;;7735:17;:39::i;:::-;7792:11;:18;;;7554:28;:270::i;:::-;7535:289:::0;7252:579;-1:-1:-1;;;;7252:579:24:o;23694:154:19:-;23780:7;23806:35;23819:6;23827:13;23806:12;:35::i;7837:580:24:-;8041:7;2970:18:6;:16;:18::i;:::-;8140:270:24::1;8186:21;8225:38;8243:11;:19;;;8225:17;:38::i;:::-;8281:22;8321:39;8339:11;:20;;;8321:17;:39::i;:::-;8378:11;:18;;;8140:28;:270::i;24472:150:19:-:0;24556:7;24582:33;24593:6;24601:13;24582:10;:33::i;19429:236::-;19495:7;19613:45;19626:31;:18;;:29;:31::i;:::-;19613:6;;:12;:45::i;25044:488::-;25102:11;25499:10;:8;:10::i;:::-;-1:-1:-1;;;;;25499:24:19;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;5229:1211:24:-;5290:16;5318:19;5340:17;:15;:17::i;:::-;5318:39;;5367:34;5418:11;5404:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5404:26:24;-1:-1:-1;5367:63:24;-1:-1:-1;5486:15:24;;5482:102;;5528:18;5505:17;5523:1;5505:20;;;;;;;;;;;;;:41;;;;;5615:1;5601:11;:15;5597:102;;;5643:18;5620:17;5638:1;5620:20;;;;;;;;;;;;;:41;;;;;5730:1;5716:11;:15;5712:102;;;5758:18;5735:17;5753:1;5735:20;;;;;;;;;;;;;:41;;;;;5845:1;5831:11;:15;5827:102;;;5873:18;5850:17;5868:1;5850:20;;;;;;;;;;;;;:41;;;;;5960:1;5946:11;:15;5942:102;;;5988:18;5965:17;5983:1;5965:20;;;;;;;;;;;;;:41;;;;;6075:1;6061:11;:15;6057:102;;;6103:18;6080:17;6098:1;6080:20;;;;;;;;;;;;;:41;;;;;6190:1;6176:11;:15;6172:102;;;6218:18;6195:17;6213:1;6195:20;;;;;;;;;;;;;:41;;;;;6305:1;6291:11;:15;6287:102;;;6333:18;6310:17;6328:1;6310:20;;;;;;;2398:1048:23;893:4:7;2537:17:23;3231:152;3255:17;:24;3251:1;:28;3231:152;;;3312:60;3330:41;3350:17;3368:1;3350:20;;;;;;;;;;;;;;3330:8;3339:1;3330:11;;;;;;;;;;;;;;:19;;:41;;;;:::i;:::-;3312:9;;:17;:60::i;:::-;3300:72;-1:-1:-1;3281:3:23;;3231:152;;;;3393:46;3414:1;3402:9;:13;6263:3:1;3393:8:23;:46::i;3199:183:10:-;3276:7;3341:20;:18;:20::i;:::-;3363:10;3312:62;;;;;;;;;:::i;8442:1234:24:-;8606:7;8615:16;2970:18:6;:16;:18::i;:::-;8798:26:24::1;8827:19;:8;:17;:19::i;:::-;8798:48:::0;-1:-1:-1;8856:66:24::1;8873:26;8865:4;:34;;;;;;;;;5443:3:1;8856:8:24;:66::i;:::-;8933:26;8962:27;:8;:25;:27::i;:::-;8933:56;;8999:72;9035:17;:15;:17::i;:::-;9054:9;:16;8999:35;:72::i;:::-;9081:43;9095:9;9106:17;:15;:17::i;9081:43::-;9135:34;9172:20;:18;:20::i;:::-;9135:57;;9203:26;9232:62;9265:17;9284:9;9232:32;:62::i;:::-;9203:91;;9510:20;9533:47;9542:18;9562:17;:15;:17::i;9533:47::-;9591:14;:35:::0;;;;-1:-1:-1;9591:35:24;9659:9;;-1:-1:-1;8442:1234:24;;-1:-1:-1;;;;;;;8442:1234:24:o;5641:242:17:-;-1:-1:-1;;;;;5742:19:17;;:8;:19;;;;;;;;;;;:31;;5766:6;5742:23;:31::i;:::-;-1:-1:-1;;;;;5720:19:17;;:8;:19;;;;;;;;;;:53;5798:12;;:24;;5815:6;5798:16;:24::i;:::-;5783:12;:39;5837;;-1:-1:-1;;;;;5837:39:17;;;5854:1;;5837:39;;;;5869:6;;5837:39;:::i;:::-;;;;;;;;5641:242;;:::o;1740:374:5:-;1836:1;1821:5;:12;:16;1817:53;;;1853:7;;1817:53;1880:16;1899:5;1905:1;1899:8;;;;;;;;;;;;;;1880:27;;1922:9;1934:1;1922:13;;1917:191;1941:5;:12;1937:1;:16;1917:191;;;1974:15;1992:5;1998:1;1992:8;;;;;;;;;;;;;;;;;;;-1:-1:-1;2014:51:5;-1:-1:-1;;;;;2023:18:5;;;;;;;4890:3:1;2014:8:5;:51::i;:::-;2090:7;-1:-1:-1;1955:3:5;;1917:191;;1908:544:20;1996:4;1602:42;2017:10;:8;:10::i;:::-;-1:-1:-1;;;;;2017:29:20;;;;;2016:63;;;2051:28;2070:8;2051:18;:28::i;:::-;2012:434;;;2211:10;:8;:10::i;:::-;-1:-1:-1;;;;;2197:24:20;:10;:24;;-1:-1:-1;2190:31:20;;2012:434;2374:16;:14;:16::i;:::-;:61;;-1:-1:-1;;;2374:61:20;;-1:-1:-1;;;;;2374:27:20;;;;;;;:61;;2402:8;;2412:7;;2429:4;;2374:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2367:68;;;;1074:3172:1;-1:-1:-1;;;3588:3:1;3581:79;;;3799:66;3793:4;3786:80;3941:1;3935:4;3928:15;2210:2;2243:18;;;2336;;;2383;;;2215:4;2379:29;;;3057:2;3053:17;2195:18;;;;2288;;;;2284:29;;;;3040:1;3036:14;3025:26;;;;3021:50;;;;2999:73;;2994:3;2990:83;4008:4;4001:26;4234:3;;4224:14;3388:427:10;3790:9;;3765:44::o;19422:1158:24:-;19676:16;19737:38;19792:17;:15;:17::i;:::-;19778:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;19778:32:24;-1:-1:-1;19737:73:24;-1:-1:-1;19906:30:24;19902:89;;19959:21;-1:-1:-1;19952:28:24;;19902:89;20280:254;20341:8;20350:20;20341:30;;;;;;;;;;;;;;20385:17;20403:20;20385:39;;;;;;;;;;;;;;20438:17;20469:16;20499:25;20280:47;:254::i;:::-;20234:21;20256:20;20234:43;;;;;;;;;;;;;;;;;:300;20552:21;-1:-1:-1;19422:1158:24;;;;;;;;:::o;21591:320::-;21788:9;21783:122;21807:17;:15;:17::i;:::-;21803:1;:21;21783:122;;;21859:35;21868:8;21877:1;21868:11;;;;;;;;;;;;;;21881:9;21891:1;21881:12;;;;;;;;;;;;;;21859:8;:35;;:::i;:::-;21845:8;21854:1;21845:11;;;;;;;;;;;;;;;;;:49;21826:3;;21783:122;;;;21591:320;;;:::o;15867:685::-;16022:7;16031:16;16059:13;16075:19;:8;:17;:19::i;:::-;16059:35;-1:-1:-1;16117:39:24;16109:4;:47;;;;;;;;;16105:441;;;16179:65;16206:8;16216:17;16235:8;16179:26;:65::i;:::-;16172:72;;;;;;;16105:441;16273:36;16265:4;:44;;;;;;;;;16261:285;;;16332:47;16360:8;16370;16332:27;:47::i;16261:285::-;16469:66;16497:8;16507:17;16526:8;16469:27;:66::i;16261:285::-;15867:685;;;;;;;;:::o;21092:329::-;21265:7;21284:52;21299:8;21309:10;21321:14;21284;:52::i;:::-;21353:61;21386:17;21405:8;21353:32;:61::i;1979:148:9:-;2041:7;2060:38;2069:6;;;4516:1:1;2060:8:9;:38::i;:::-;2119:1;2115;:5;;;;;;;1979:148;-1:-1:-1;;;1979:148:9:o;11445:610:24:-;11600:7;11609:16;11637:13;11653:19;:8;:17;:19::i;:::-;11637:35;-1:-1:-1;11695:36:24;11687:4;:44;;;;;;;;;11683:366;;;11754:66;11782:8;11792:17;11811:8;11754:27;:66::i;11683:366::-;11849:35;11841:4;:43;;;;;;;;;11837:212;;;11907:65;11934:8;11944:17;11963:8;11907:26;:65::i;11837:212::-;12003:35;6211:3:1;12003:7:24;:35::i;20759:327::-;20931:7;20950:51;20965:8;20975:9;20986:14;20950;:51::i;2133:232:9:-;2193:7;2212:38;2221:6;;;4516:1:1;2212:8:9;:38::i;:::-;2265:6;2261:98;;-1:-1:-1;2294:1:9;2287:8;;2261:98;2347:1;2342;2338;:5;2337:11;;;;;;2333:1;:15;2326:22;;;;1862:617:7;1922:7;1959:5;;;1974:57;1983:6;;;:26;;;2008:1;2003;1993:7;:11;;;;1974:57;2046:12;2042:431;;2081:1;2074:8;;;;;2042:431;893:4;-1:-1:-1;;2439:11:7;;2438:19;;2461:1;2437:25;2430:32;;;;;4517:706:24;4589:7;4648;-1:-1:-1;;;;;4639:16:24;;;;;;;4635:582;;;-1:-1:-1;4666:18:24;4659:25;;4635:582;4714:7;-1:-1:-1;;;;;4705:16:24;;;;;;;4701:516;;;-1:-1:-1;4732:18:24;4725:25;;4701:516;4780:7;-1:-1:-1;;;;;4771:16:24;;;;;;;4767:450;;;-1:-1:-1;4798:18:24;4791:25;;4767:450;4846:7;-1:-1:-1;;;;;4837:16:24;;;;;;;4833:384;;;-1:-1:-1;4864:18:24;4857:25;;4833:384;4912:7;-1:-1:-1;;;;;4903:16:24;;;;;;;4899:318;;;-1:-1:-1;4930:18:24;4923:25;;4899:318;4978:7;-1:-1:-1;;;;;4969:16:24;;;;;;;4965:252;;;-1:-1:-1;4996:18:24;4989:25;;4965:252;5044:7;-1:-1:-1;;;;;5035:16:24;;;;;;;5031:186;;;-1:-1:-1;5062:18:24;5055:25;;5031:186;5110:7;-1:-1:-1;;;;;5101:16:24;;;;;;;5097:120;;;-1:-1:-1;5128:18:24;5121:25;;3582:1761:23;3770:7;4994:75;5015:32;:9;1707:6;5015:17;:32::i;:::-;5003:8;:44;;5863:3:1;4994:8:23;:75::i;:::-;5080:19;5102:23;:9;5116:8;5102:13;:23::i;:::-;5080:45;-1:-1:-1;5135:12:23;5150:28;:9;5080:45;5150:15;:28::i;:::-;5135:43;-1:-1:-1;5188:16:23;5207:27;:8;5224:9;5207:16;:27::i;:::-;5188:46;-1:-1:-1;5244:13:23;5260:20;:4;5188:46;5260:10;:20::i;:::-;5244:36;;5298:38;5317:18;:5;:16;:18::i;:::-;5298:10;;:18;:38::i;:::-;5291:45;3582:1761;-1:-1:-1;;;;;;;;;;3582:1761:23:o;5481:1920::-;5670:7;6875:79;6897:34;:10;1762:6;6897:18;:34::i;:::-;6884:9;:47;;5914:3:1;6875:8:23;:79::i;:::-;6965:12;6980:43;6997:25;:10;7012:9;6997:14;:25::i;:::-;6980:10;;:16;:43::i;:::-;6965:58;-1:-1:-1;7033:16:23;7052:25;:9;7068:8;7052:15;:25::i;:::-;7033:44;-1:-1:-1;7087:13:23;7103:20;:4;7033:44;7103:10;:20::i;:::-;7087:36;-1:-1:-1;7313:13:23;7329:25;7087:36;893:4:7;7329:9:23;:25::i;:::-;7313:41;-1:-1:-1;7372:22:23;:9;7313:41;7372:15;:22::i;4812:112:7:-;4866:7;893:4;4893:1;:7;4892:25;;4916:1;4892:25;;;-1:-1:-1;893:4:7;4905:7;;4812:112::o;2846:682::-;2906:7;2925:38;2934:6;;;4516:1:1;2925:8:7;:38::i;:::-;2978:6;2974:548;;-1:-1:-1;3007:1:7;3000:8;;2974:548;893:4;3059:7;;;;3080:51;;3059:1;:7;:1;3089:13;;;3080:51;3505:1;3500;3488:9;:13;3487:19;;;;3760:312;3822:7;3841:11;3855:20;3870:1;3873;3855:14;:20::i;:::-;3841:34;;3885:16;3904:42;3908:34;3914:3;975:5;3908;:34::i;:::-;3944:1;3904:3;:42::i;:::-;3885:61;;3967:8;3961:3;:14;3957:109;;;3998:1;3991:8;;;;;;3957:109;4037:18;4041:3;4046:8;4037:3;:18::i;:::-;4030:25;;;;;;1647:209;1709:7;1746:5;;;1761:57;1770:6;;;:26;;;1795:1;1790;1780:7;:11;;;;1761:57;893:4;1836:13;;;;-1:-1:-1;;;1647:209:7:o;830:148:26:-;890:21;941:4;930:41;;;;;;;;;;;;:::i;1152:181::-;1220:26;1285:4;1274:52;;;;;;;;;;;;:::i;2458:246:20:-;2526:4;2646:51;-1:-1:-1;;;2646:11:20;:51::i;:::-;2634:63;;;;2458:246;-1:-1:-1;2458:246:20:o;16972:1963:23:-;17216:7;17563:17;17543:16;:37;17539:312;;-1:-1:-1;17839:1:23;17832:8;;17539:312;18225:12;18240:41;:17;18264:16;18240:23;:41::i;:::-;18225:56;-1:-1:-1;18291:16:23;18310:40;893:4:7;18333:16:23;18310:22;:40::i;:::-;18291:59;;18687:53;18696:4;1144:6:7;18687:8:23;:53::i;:::-;18680:60;-1:-1:-1;18751:13:23;18767:20;18680:60;18778:8;18767:10;:20::i;:::-;18751:36;;18798:24;18825:35;18841:18;:5;:16;:18::i;:::-;18825:7;;:15;:35::i;:::-;18798:62;-1:-1:-1;18877:51:23;18798:62;18902:25;18877:24;:51::i;16558:1052:24:-;16746:7;16755:16;2970:18:6;:16;:18::i;:::-;16854:19:24::1;16875:18:::0;16897:32:::1;:8;:30;:32::i;:::-;16853:76;;;;17040:62;17062:17;:15;:17::i;:::-;17049:10;:30;4838:3:1;17040:8:24;:62::i;:::-;17190:27;17234:17;:15;:17::i;:::-;17220:32;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;17220:32:24::1;;17190:62;;17348:212;17403:8;17412:10;17403:20;;;;;;;;;;;;;;17437:17;17455:10;17437:29;;;;;;;;;;;;;;17480:11;17505:13;:11;:13::i;:::-;17532:18;;17348:41;:212::i;:::-;17323:10;17334;17323:22;;;;;;;;;::::0;;::::1;::::0;;;;;:237;17579:11;;;;-1:-1:-1;16558:1052:24;;-1:-1:-1;;;;;16558:1052:24:o;17616:910::-;17749:7;17758:16;18201:19;18223:33;:8;:31;:33::i;:::-;18201:55;;18367:27;18397:80;18440:8;18450:11;18463:13;:11;:13::i;:::-;18397:42;:80::i;:::-;18495:11;;;;-1:-1:-1;17616:910:24;;-1:-1:-1;;;;17616:910:24:o;18532:868::-;18721:7;18730:16;2970:18:6;:16;:18::i;:::-;18829:27:24::1;18858:22;18884:33;:8;:31;:33::i;:::-;18828:89;;;;18927:73;18963:10;:17;18982;:15;:17::i;18927:73::-;19010:44;19024:10;19036:17;:15;:17::i;19010:44::-;19065:19;19087:188;19143:8;19165:17;19196:10;19220:13;:11;:13::i;:::-;19247:18;;19087:42;:188::i;:::-;19065:210;;19285:65;19309:14;19294:11;:29;;5498:3:1;19285:8:24;:65::i;:::-;19369:11:::0;19382:10;;-1:-1:-1;18532:868:24;;-1:-1:-1;;;;;18532:868:24:o;12061:787::-;12236:7;12245:16;12274:26;12302:23;12329:33;:8;:31;:33::i;:::-;12273:89;;;;12372:72;12408:17;:15;:17::i;:::-;12427:9;:16;12372:35;:72::i;:::-;12455:43;12469:9;12480:17;:15;:17::i;12455:43::-;12509:20;12532:187;12588:8;12610:17;12641:9;12664:13;:11;:13::i;:::-;12691:18;;12532:42;:187::i;:::-;12509:210;;12730:68;12755:15;12739:12;:31;;5554:3:1;12730:8:24;:68::i;12854:829::-;13028:7;13037:16;13066:20;13088:18;13110:32;:8;:30;:32::i;:::-;13065:77;;;;13252:62;13274:17;:15;:17::i;13252:62::-;13325:26;13368:17;:15;:17::i;:::-;13354:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;13354:32:24;;13325:61;;13420:213;13475:8;13484:10;13475:20;;;;;;;;;;;;;;13509:17;13527:10;13509:29;;;;;;;;;;;;;;13552:12;13578:13;:11;:13::i;:::-;13605:18;;13420:41;:213::i;4302:227:7:-;4362:7;4381:11;4395:20;4410:1;4413;4395:14;:20::i;:::-;4381:34;;4425:16;4444:42;4448:34;4454:3;975:5;4448;:34::i;4444:42::-;4425:61;;4504:18;4508:3;4513:8;4504:3;:18::i;4463:2190:8:-;4521:7;4544:6;4540:131;;-1:-1:-1;1533:4:8;4638:22;;4540:131;4685:6;4681:45;;-1:-1:-1;4714:1:8;4707:8;;4681:45;5096:44;-1:-1:-1;;;5105:10:8;;4615:1:1;5096:8:8;:44::i;:::-;5175:1;5531:57;2676:24;5540:23;;4666:1:1;5531:8:8;:57::i;:::-;5623:1;5598:15;2562:13;5669:28;-1:-1:-1;5669:60:8;;;;-1:-1:-1;2617:13:8;5701:28;;5669:60;5665:682;;;5745:14;5762:15;5768:8;5762:5;:15::i;:::-;5745:32;-1:-1:-1;1533:4:8;6228:16;;;6227:29;;6226:40;6215:8;1533:4;6195:7;:16;6194:29;:72;6178:89;;5665:682;;;;6328:8;6313:12;6316:8;6313:2;:12::i;:::-;:23;6298:38;;5665:682;1533:4;6356:22;;6452:150;-1:-1:-1;;;;6474:36:8;;;:76;;;2318:6;6514:12;:36;;6474:76;4723:1:1;6452:8:8;:150::i;:::-;6628:17;6632:12;6628:3;:17::i;:::-;6613:33;4463:2190;-1:-1:-1;;;;;;4463:2190:8:o;1495:105:9:-;1553:7;1584:1;1579;:6;;:14;;1592:1;1579:14;;;-1:-1:-1;1588:1:9;;1495:105;-1:-1:-1;1495:105:9:o;1853:220:26:-;1926:19;1947:18;2018:4;2007:59;;;;;;;;;;;;:::i;:::-;1977:89;;;;-1:-1:-1;1853:220:26;-1:-1:-1;;;1853:220:26:o;12979:2534:23:-;13191:7;;14334:53;14372:14;14334:31;14372:14;14353:11;14334:18;:31::i;:::-;:37;;:53::i;:::-;14309:78;;14397:81;2119:6;14406:14;:38;;5976:3:1;14397:8:23;:81::i;:::-;14580:20;14603:62;14624:40;893:4:7;14647:16:23;14624:22;:40::i;:::-;14603:14;;:20;:62::i;:::-;14580:85;;14784:27;14814:42;14830:25;:12;:23;:25::i;:::-;14814:7;;:15;:42::i;:::-;14784:72;;15012:25;15040:29;:16;:27;:29::i;:::-;15012:57;-1:-1:-1;15280:21:23;15304:44;:19;15012:57;15304:25;:44::i;:::-;15280:68;-1:-1:-1;15358:24:23;15385:38;:19;15280:68;15385:23;:38::i;:::-;15358:65;;15441;15462:43;15484:20;:7;:18;:20::i;:::-;15462:13;;:21;:43::i;:::-;15441:16;;:20;:65::i;:::-;15434:72;12979:2534;-1:-1:-1;;;;;;;;;;;;12979:2534:23:o;2079:180:26:-;2153:19;2213:4;2202:50;;;;;;;;;;;;:::i;15519:1447:23:-;15677:16;16687;16706:29;:11;16726:8;16706:19;:29::i;:::-;16687:48;;16746:27;16790:8;:15;16776:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16776:30:23;;16746:60;;16821:9;16816:116;16840:8;:15;16836:1;:19;16816:116;;;16892:29;16912:8;16892;16901:1;16892:11;;;;;;;;;;;;;;:19;;:29;;;;:::i;:::-;16876:10;16887:1;16876:13;;;;;;;;;;;;;;;;;:45;16857:3;;16816:116;;;-1:-1:-1;16949:10:23;15519:1447;-1:-1:-1;;;;;15519:1447:23:o;2265:266:26:-;2363:27;2392:22;2474:4;2463:61;;;;;;;;;;;;:::i;11171:1802:23:-;11412:7;11475:40;11532:10;:17;11518:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11518:32:23;;11475:75;;11560:33;11612:9;11607:306;11631:8;:15;11627:1;:19;11607:306;;;11696:49;11733:8;11742:1;11733:11;;;;;;;;;;;;;;11696:30;11712:10;11723:1;11712:13;;;;;;;;;;;;;;11696:8;11705:1;11696:11;;;;;;;;;;;;;;:15;;:30;;;;:::i;:49::-;11667:23;11691:1;11667:26;;;;;;;;;;;;;:78;;;;;11787:115;11834:54;11867:17;11885:1;11867:20;;;;;;;;;;;;;;11834:23;11858:1;11834:26;;;;;;;;;;;;;;:32;;:54;;;;:::i;:::-;11787:25;;:29;:115::i;:::-;11759:143;-1:-1:-1;11648:3:23;;11607:306;;;-1:-1:-1;893:4:7;11923:22:23;11972:928;11996:8;:15;11992:1;:19;11972:928;;;12234:24;12304:23;12328:1;12304:26;;;;;;;;;;;;;;12276:25;:54;12272:428;;;12350:24;12377:59;12397:38;:25;:36;:38::i;:::-;12377:8;12386:1;12377:11;;;;;;;:59;12350:86;;12454:21;12478:35;12496:16;12478:10;12489:1;12478:13;;;;;;;:35;12454:59;;12551:63;12572:41;12592:20;:7;:18;:20::i;12551:63::-;12532:82;;12272:428;;;;;12672:10;12683:1;12672:13;;;;;;;;;;;;;;12653:32;;12272:428;12714:20;12737:54;12779:8;12788:1;12779:11;;;;;;;;;;;;;;12737:33;12753:16;12737:8;12746:1;12737:11;;;;;;;:54;12714:77;;12823:66;12846:42;12867:17;12885:1;12867:20;;;;;;;;;;;;;;12846:12;:20;;:42;;;;:::i;:::-;12823:14;;:22;:66::i;:::-;12806:83;-1:-1:-1;;;12013:3:23;;11972:928;;;;12917:49;12938:27;:14;:25;:27::i;:::-;12917:14;;:20;:49::i;:::-;12910:56;11171:1802;-1:-1:-1;;;;;;;;;11171:1802:23:o;7407:1680::-;7647:7;7713:37;7767:9;:16;7753:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7753:31:23;;7713:71;;7795:30;7844:9;7839:267;7863:8;:15;7859:1;:19;7839:267;;;7925:50;7963:8;7972:1;7963:11;;;;;;;;;;;;;;7925:29;7941:9;7951:1;7941:12;;;;;;;;;;;;;;7925:8;7934:1;7925:11;;;;;;;;;;;;;;:15;;:29;;;;:::i;:50::-;7899:20;7920:1;7899:23;;;;;;;;;;;;;:76;;;;;8014:81;8041:53;8073:17;8091:1;8073:20;;;;;;;;;;;;;;8041;8062:1;8041:23;;;;;;;8014:81;7989:106;-1:-1:-1;7880:3:23;;7839:267;;;-1:-1:-1;893:4:7;8116:22:23;8165:739;8189:8;:15;8185:1;:19;8165:739;;;8225:26;8296:22;8270:20;8291:1;8270:23;;;;;;;;;;;;;;:48;8266:436;;;8338:24;8365:63;8385:42;:22;893:4:7;8385:26:23;:42::i;8365:63::-;8338:90;;8446:21;8470:34;8487:16;8470:9;8480:1;8470:12;;;;;;;:34;8446:58;-1:-1:-1;8543:72:23;8564:50;8586:27;893:4:7;8605:7:23;8586:18;:27::i;8543:72::-;8522:93;;8266:436;;;;;8675:9;8685:1;8675:12;;;;;;;;;;;;;;8654:33;;8266:436;8716:20;8739:56;8783:8;8792:1;8783:11;;;;;;;;;;;;;;8739:35;8755:18;8739:8;8748:1;8739:11;;;;;;;:56;8716:79;;8827:66;8850:42;8871:17;8889:1;8871:20;;;;;;;8827:66;8810:83;-1:-1:-1;;;8206:3:23;;8165:739;;;;893:4:7;8918:14:23;:32;8914:167;;8973:58;8996:34;:14;893:4:7;8996:18:23;:34::i;:::-;8973:14;;:22;:58::i;:::-;8966:65;;;;;;;8914:167;9069:1;9062:8;;;;;;;9093:2072;9306:7;;10293:54;10332:14;10293:32;10332:14;10312:12;10293:18;:32::i;:54::-;10268:79;;10357:81;1942:4;10366:14;:38;;6038:3:1;10357:8:23;:81::i;:::-;10544:20;10567:60;10588:38;893:4:7;10609:16:23;10588:20;:38::i;10567:60::-;10544:83;-1:-1:-1;10638:26:23;10667:47;10681:32;10544:83;893:4:7;10681:16:23;:32::i;:::-;10667:7;;:13;:47::i;:::-;10638:76;;10869:25;10897:29;:16;:27;:29::i;:::-;10869:57;-1:-1:-1;10936:21:23;10960:43;:18;10869:57;10960:24;:43::i;:::-;10936:67;-1:-1:-1;11013:24:23;11040:37;:18;10936:67;11040:22;:37::i;:::-;11013:64;;11095:63;11116:41;11136:20;:7;:18;:20::i;:::-;11116:13;;:19;:41::i;18640:1713:8:-;1533:4;18909:11;18687:6;;1758:4;19319:10;;;;-1:-1:-1;;19294:10:8;;19293:21;19319:10;19292:38;;;;;;-1:-1:-1;19340:16:8;1758:4;19360:5;;;19359:16;;-1:-1:-1;19469:1:8;;1758:4;19684:15;;;19683:26;;-1:-1:-1;19738:1:8;19683:26;19732:7;19719:20;1758:4;19757:15;;;19756:26;;-1:-1:-1;19811:1:8;19756:26;19805:7;19792:20;1758:4;19830:15;;;19829:26;;-1:-1:-1;19884:1:8;19829:26;19878:7;19865:20;1758:4;19903:15;;;19902:26;;-1:-1:-1;19957:1:8;19902:26;19951:7;19938:20;1758:4;19976:15;;;19975:26;;-1:-1:-1;20030:2:8;19975:26;20024:8;20011:21;1758:4;20050:15;;;20049:26;;-1:-1:-1;20104:2:8;20049:26;20098:8;20085:21;1758:4;20124:15;;;20123:26;;-1:-1:-1;20178:2:8;20123:26;20345:1;20172:8;;;20159:21;;;;20333:13;;18640:1713;-1:-1:-1;;;;;18640:1713:8:o;12351:5089::-;12396:6;12497:37;12510:1;12506;:5;4838:3:1;12497:8:8;:37::i;:::-;1533:4;12549:1;:10;12545:381;;;12889:25;12912:1;12893:15;12912:1;12892:21;;;;;12889:2;:25::i;:::-;12888:26;;12880:35;;;;12545:381;14251:10;14284:11;14279:16;;14275:114;;2812:56;14311:7;;;-1:-1:-1;2756:21:8;14369:9;14275:114;14408:11;14403:16;;14399:114;;2975:28;14435:7;;;-1:-1:-1;2920:20:8;14493:9;14399:114;14651:3;14664:8;;;;14644:10;3141:34;14799:7;;14795:82;;3141:34;1723:4;14827:10;;14826:17;;-1:-1:-1;3084:22:8;14857:9;14795:82;3270:27;14891:1;:7;14887:82;;3270:27;1723:4;14919:10;;14918:17;;-1:-1:-1;3213:22:8;14949:9;14887:82;3391:24;14983:1;:7;14979:82;;3391:24;1723:4;15011:10;;15010:17;;-1:-1:-1;3335:21:8;15041:9;14979:82;3509:22;15075:1;:7;15071:82;;3509:22;1723:4;15103:10;;15102:17;;-1:-1:-1;3453:21:8;15133:9;15071:82;3625:21;15167:1;:7;15163:82;;3625:21;1723:4;15195:10;;15194:17;;-1:-1:-1;3569:21:8;15225:9;15163:82;3740:21;15259:1;:7;15255:82;;3740:21;1723:4;15287:10;;;15286:17;;15317:9;15255:82;3855:21;15351:1;:7;15347:82;;3855:21;1723:4;15379:10;;15378:17;;-1:-1:-1;3799:20:8;15409:9;15347:82;3970:21;15443:1;:7;15439:82;;3970:21;1723:4;15471:10;;15470:17;;-1:-1:-1;3914:20:8;15501:9;15439:82;4087:21;15535:1;:8;15531:85;;4087:21;1723:4;15564:10;;15563:18;;-1:-1:-1;4030:20:8;15595:10;15531:85;4204:21;15630:1;:8;15626:85;;4204:21;1723:4;15659:10;;15658:18;;-1:-1:-1;4148:19:8;15690:10;15626:85;16213:8;1723:4;16251:1;:10;1723:4;;16226:1;:10;16225:21;16224:38;;;;;;;-1:-1:-1;16272:16:8;1723:4;16292:5;;;16291:16;;-1:-1:-1;16401:1:8;;1723:4;16616:15;;;16615:26;;-1:-1:-1;16670:1:8;16615:26;16664:7;16651:20;1723:4;16689:15;;;16688:26;;-1:-1:-1;16743:1:8;16688:26;16737:7;16724:20;1723:4;16762:15;;;16761:26;;-1:-1:-1;16816:1:8;16761:26;16810:7;16797:20;1723:4;16835:15;;;16834:26;;-1:-1:-1;16889:1:8;16834:26;16883:7;16870:20;1723:4;16908:15;;;16907:26;;-1:-1:-1;16962:2:8;16907:26;16956:8;16943:21;17136:1;17123:14;17430:3;17411:15;;;17410:23;;12351:5089;-1:-1:-1;;;;;;;12351:5089:8:o;6867:5379::-;6913:6;6931:89;-1:-1:-1;;6940:25:8;;;;;:54;;;2318:6;6969:1;:25;;6940:54;4775:1:1;6931:8:8;:89::i;:::-;7039:1;7035;:5;7031:353;;;7365:7;7370:1;7369:2;;7365:3;:7::i;:::-;7346:15;7345:27;;;;;;7337:36;;;;7031:353;8685:14;2756:21;8713:1;:7;8709:220;;-1:-1:-1;;;8736:7:8;;;;2812:56;8709:220;;;2920:20;8790:1;:7;8786:143;;-1:-1:-1;;;8813:7:8;;;;2975:28;8786:143;;;-1:-1:-1;8887:1:8;8786:143;9084:3;9079:8;;;;;1723:4;3084:22;9338:7;;9334:92;;-1:-1:-1;;9361:7:8;;;;;1723:4;3141:34;9393:12;;;9392:23;9334:92;3213:22;9439:1;:7;9435:92;;-1:-1:-1;;9462:7:8;;;;;1723:4;3270:27;9494:12;;;9493:23;9435:92;3335:21;9540:1;:7;9536:92;;-1:-1:-1;;9563:7:8;;;;;1723:4;3391:24;9595:12;;;9594:23;9536:92;3453:21;9641:1;:7;9637:92;;-1:-1:-1;;9664:7:8;;;;;1723:4;3509:22;9696:12;;;9695:23;9637:92;3569:21;9742:1;:7;9738:92;;-1:-1:-1;;9765:7:8;;;;;1723:4;3625:21;9797:12;;;9796:23;9738:92;3684:21;9843:1;:7;9839:92;;-1:-1:-1;;9866:7:8;;;;;3684:21;3740;9898:12;;;9897:23;9839:92;3799:20;9944:1;:7;9940:92;;-1:-1:-1;;9967:7:8;;;;;1723:4;3855:21;9999:12;;;9998:23;9940:92;3914:20;10045:1;:7;10041:92;;-1:-1:-1;;10068:7:8;;;;;1723:4;3970:21;10100:12;;;10099:23;10041:92;1723:4;10665:17;;;;;;10950:1;;10928:8;;;10927:19;10926:25;10961:17;;;;10926:25;-1:-1:-1;11020:1:8;1723:4;10998:8;;;10997:19;10996:25;11031:17;;;;10996:25;-1:-1:-1;11090:1:8;1723:4;11068:8;;;11067:19;11066:25;11101:17;;;;11066:25;-1:-1:-1;11160:1:8;1723:4;11138:8;;;11137:19;11136:25;11171:17;;;;11136:25;-1:-1:-1;11230:1:8;1723:4;11208:8;;;11207:19;11206:25;11241:17;;;;11206:25;-1:-1:-1;11300:1:8;1723:4;11278:8;;;11277:19;11276:25;11311:17;;;;11276:25;-1:-1:-1;11370:1:8;1723:4;11348:8;;;11347:19;11346:25;11381:17;;;;11346:25;-1:-1:-1;11440:1:8;1723:4;11418:8;;;11417:19;11416:25;11451:17;;;;11416:25;-1:-1:-1;11510:2:8;1723:4;11488:8;;;11487:19;11486:26;11522:17;;;;11486:26;-1:-1:-1;11581:2:8;1723:4;11559:8;;;11558:19;11557:26;11593:17;;;;11557:26;-1:-1:-1;11652:2:8;1723:4;11630:8;;;11629:19;11628:26;11664:17;;;;11628:26;-1:-1:-1;12236:3:8;1723:4;12192:19;;;12191:30;12190:42;;12189:50;;6867:5379;-1:-1:-1;;;;;;6867:5379:8:o;5:130:-1:-;72:20;;97:33;72:20;97:33;:::i;1694:722::-;;1822:3;1815:4;1807:6;1803:17;1799:27;1789:2;;-1:-1;;1830:12;1789:2;1870:6;1864:13;1892:80;1907:64;1964:6;1907:64;:::i;:::-;1892:80;:::i;:::-;2000:21;;;1883:89;-1:-1;2044:4;2057:14;;;;2032:17;;;2146;;;2137:27;;;;2134:36;-1:-1;2131:2;;;2183:1;;2173:12;2131:2;2208:1;2193:217;2218:6;2215:1;2212:13;2193:217;;;6343:13;;2286:61;;2361:14;;;;2389;;;;2240:1;2233:9;2193:217;;;2197:14;;;;;1782:634;;;;:::o;2963:440::-;;3064:3;3057:4;3049:6;3045:17;3041:27;3031:2;;-1:-1;;3072:12;3031:2;3119:6;3106:20;29305:18;29297:6;29294:30;29291:2;;;-1:-1;;29327:12;29291:2;3141:64;29468:4;-1:-1;;29400:9;29381:17;;29377:33;29458:15;3141:64;:::i;:::-;3132:73;;3225:6;3218:5;3211:21;3329:3;29468:4;3320:6;3253;3311:16;;3308:25;3305:2;;;3346:1;;3336:12;3305:2;32321:6;29468:4;3253:6;3249:17;29468:4;3287:5;3283:16;32298:30;32377:1;32359:16;;;29468:4;32359:16;32352:27;3287:5;3024:379;-1:-1;;3024:379::o;4264:156::-;4344:20;;34052:1;34042:12;;34032:2;;34068:1;;34058:12;6539:241;;6643:2;6631:9;6622:7;6618:23;6614:32;6611:2;;;-1:-1;;6649:12;6611:2;85:6;72:20;97:33;124:5;97:33;:::i;6787:366::-;;;6908:2;6896:9;6887:7;6883:23;6879:32;6876:2;;;-1:-1;;6914:12;6876:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;6966:63;-1:-1;7066:2;7105:22;;72:20;97:33;72:20;97:33;:::i;:::-;7074:63;;;;6870:283;;;;;:::o;7160:491::-;;;;7298:2;7286:9;7277:7;7273:23;7269:32;7266:2;;;-1:-1;;7304:12;7266:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;7356:63;-1:-1;7456:2;7495:22;;72:20;97:33;72:20;97:33;:::i;:::-;7260:391;;7464:63;;-1:-1;;;7564:2;7603:22;;;;6195:20;;7260:391::o;7658:991::-;;;;;;;;7862:3;7850:9;7841:7;7837:23;7833:33;7830:2;;;-1:-1;;7869:12;7830:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;7921:63;-1:-1;8021:2;8060:22;;72:20;97:33;72:20;97:33;:::i;:::-;8029:63;-1:-1;8129:2;8168:22;;6195:20;;-1:-1;8237:2;8276:22;;6195:20;;-1:-1;8345:3;8383:22;;6471:20;31631:4;31620:16;;34265:33;;34255:2;;-1:-1;;34302:12;34255:2;7824:825;;;;-1:-1;7824:825;;;;8354:61;8452:3;8492:22;;2757:20;;-1:-1;8561:3;8601:22;;;2757:20;;7824:825;-1:-1;;7824:825::o;8656:366::-;;;8777:2;8765:9;8756:7;8752:23;8748:32;8745:2;;;-1:-1;;8783:12;8745:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;8835:63;8935:2;8974:22;;;;6195:20;;-1:-1;;;8739:283::o;9029:823::-;;;;9243:2;9231:9;9222:7;9218:23;9214:32;9211:2;;;-1:-1;;9249:12;9211:2;9300:17;9294:24;9338:18;;9330:6;9327:30;9324:2;;;-1:-1;;9360:12;9324:2;9477:6;9466:9;9462:22;;;311:3;304:4;296:6;292:17;288:27;278:2;;-1:-1;;319:12;278:2;359:6;353:13;381:95;396:79;468:6;396:79;:::i;381:95::-;482:16;518:6;511:5;504:21;548:4;;565:3;561:14;554:21;;548:4;540:6;536:17;670:3;548:4;;654:6;650:17;540:6;641:27;;638:36;635:2;;;-1:-1;;677:12;635:2;-1:-1;703:10;;697:232;722:6;719:1;716:13;697:232;;;3858:6;3852:13;3870:48;3912:5;3870:48;:::i;:::-;790:76;;744:1;737:9;;;;;880:14;;;;908;;697:232;;;-1:-1;9537:18;;9531:25;9380:114;;-1:-1;9531:25;-1:-1;;;9565:30;;;9562:2;;;-1:-1;;9598:12;9562:2;;9628:89;9709:7;9700:6;9689:9;9685:22;9628:89;:::i;:::-;9618:99;;;9754:2;9808:9;9804:22;6343:13;9762:74;;9205:647;;;;;:::o;9859:235::-;;9960:2;9948:9;9939:7;9935:23;9931:32;9928:2;;;-1:-1;;9966:12;9928:2;2501:6;2488:20;2513:30;2537:5;2513:30;:::i;10101:257::-;;10213:2;10201:9;10192:7;10188:23;10184:32;10181:2;;;-1:-1;;10219:12;10181:2;2636:6;2630:13;2648:30;2672:5;2648:30;:::i;10365:1235::-;;;;;;;;10605:3;10593:9;10584:7;10580:23;10576:33;10573:2;;;-1:-1;;10612:12;10573:2;2770:6;2757:20;10664:63;;10764:2;;10807:9;10803:22;72:20;97:33;124:5;97:33;:::i;:::-;10772:63;-1:-1;10872:2;10911:22;;72:20;97:33;72:20;97:33;:::i;:::-;10880:63;-1:-1;11008:2;10993:18;;10980:32;11032:18;11021:30;;;11018:2;;;-1:-1;;11054:12;11018:2;11145:6;11134:9;11130:22;;;1078:3;1071:4;1063:6;1059:17;1055:27;1045:2;;-1:-1;;1086:12;1045:2;1133:6;1120:20;1155:80;1170:64;1227:6;1170:64;:::i;1155:80::-;1241:16;1277:6;1270:5;1263:21;10764:2;1324:3;1320:14;1313:21;;10764:2;1299:6;1295:17;1429:3;10764:2;;1413:6;1409:17;1299:6;1400:27;;1397:36;1394:2;;;-1:-1;;1436:12;1394:2;-1:-1;1462:10;;1456:206;1481:6;1478:1;1475:13;1456:206;;;6195:20;;1549:50;;1503:1;1496:9;;;;;1613:14;;;;1641;;1456:206;;;-1:-1;11074:88;-1:-1;;;11199:3;11239:22;;6195:20;;-1:-1;11308:3;11348:22;;6195:20;;-1:-1;11445:3;11430:19;;11417:33;;-1:-1;11459:30;;;11456:2;;;-1:-1;;11492:12;11456:2;;;11522:62;11576:7;11567:6;11556:9;11552:22;11522:62;:::i;:::-;11512:72;;;10567:1033;;;;;;;;;;:::o;11607:239::-;;11710:2;11698:9;11689:7;11685:23;11681:32;11678:2;;;-1:-1;;11716:12;11678:2;2893:20;;-1:-1;;;;;;31032:78;;33360:34;;33350:2;;-1:-1;;33398:12;11853:303;;11988:2;11976:9;11967:7;11963:23;11959:32;11956:2;;;-1:-1;;11994:12;11956:2;3515:6;3509:13;3527:53;3574:5;3527:53;:::i;12163:289::-;;12291:2;12279:9;12270:7;12266:23;12262:32;12259:2;;;-1:-1;;12297:12;12259:2;4027:6;4021:13;4039:46;4079:5;4039:46;:::i;12459:690::-;;;;12646:2;12634:9;12625:7;12621:23;12617:32;12614:2;;;-1:-1;;12652:12;12614:2;4027:6;4021:13;4039:46;4079:5;4039:46;:::i;:::-;12849:2;12834:18;;12828:25;12704:87;;-1:-1;12873:18;12862:30;;12859:2;;;-1:-1;;12895:12;12859:2;12925:89;13006:7;12997:6;12986:9;12982:22;12925:89;:::i;13156:425::-;;;13301:2;13289:9;13280:7;13276:23;13272:32;13269:2;;;-1:-1;;13307:12;13269:2;4027:6;4021:13;4039:46;4079:5;4039:46;:::i;:::-;13483:2;13533:22;;;;6343:13;13359:87;;6343:13;;-1:-1;;;13263:318::o;13588:561::-;;;;13750:2;13738:9;13729:7;13725:23;13721:32;13718:2;;;-1:-1;;13756:12;13718:2;4027:6;4021:13;4039:46;4079:5;4039:46;:::i;:::-;13932:2;13982:22;;6343:13;14051:2;14101:22;;;6343:13;13808:87;;6343:13;;-1:-1;6343:13;13712:437;-1:-1;;;13712:437::o;14452:554::-;;;14622:2;14610:9;14601:7;14597:23;14593:32;14590:2;;;-1:-1;;14628:12;14590:2;4027:6;4021:13;4039:46;4079:5;4039:46;:::i;:::-;14825:2;14810:18;;14804:25;14680:87;;-1:-1;14849:18;14838:30;;14835:2;;;-1:-1;;14871:12;14835:2;14901:89;14982:7;14973:6;14962:9;14958:22;14901:89;:::i;:::-;14891:99;;;14584:422;;;;;:::o;16278:635::-;;;;16445:2;16433:9;16424:7;16420:23;16416:32;16413:2;;;-1:-1;;16451:12;16413:2;16509:17;16496:31;16547:18;;16539:6;16536:30;16533:2;;;-1:-1;;16569:12;16533:2;16664:6;16653:9;16649:22;;;4587:6;;4575:9;4570:3;4566:19;4562:32;4559:2;;;-1:-1;;4597:12;4559:2;4625:22;4587:6;4625:22;:::i;:::-;4616:31;;4729:62;4787:3;4763:22;4729:62;:::i;:::-;4711:16;4704:88;4889:64;4949:3;4856:2;4929:9;4925:22;4889:64;:::i;:::-;4856:2;4875:5;4871:16;4864:90;5052:64;5112:3;5019:2;5092:9;5088:22;5052:64;:::i;:::-;5019:2;5038:5;5034:16;5027:90;16445:2;5238:9;5234:22;6195:20;16445:2;5199:5;5195:16;5188:75;5326:3;5385:9;5381:22;2757:20;5326:3;5346:5;5342:16;5335:75;5482:3;5541:9;5537:22;6195:20;5482:3;5502:5;5498:16;5491:75;5661:49;5706:3;5627;5686:9;5682:22;5661:49;:::i;:::-;5627:3;5647:5;5643:16;5636:75;5804:49;5849:3;5770;5829:9;5825:22;5804:49;:::i;:::-;5770:3;5790:5;5786:16;5779:75;5947:3;;5936:9;5932:19;5919:33;16547:18;5964:6;5961:30;5958:2;;;-1:-1;;5994:12;5958:2;6041:58;6095:3;6086:6;6075:9;6071:22;6041:58;:::i;:::-;6021:18;;;6014:86;;;;-1:-1;6025:5;4856:2;16757:22;;6195:20;;-1:-1;5019:2;16865:22;;;6195:20;;16407:506;-1:-1;;;;;16407:506::o;16920:241::-;;17024:2;17012:9;17003:7;16999:23;16995:32;16992:2;;;-1:-1;;17030:12;16992:2;-1:-1;6195:20;;16986:175;-1:-1;16986:175::o;17501:690::-;;17694:5;29751:12;30167:6;30162:3;30155:19;30204:4;;30199:3;30195:14;17706:93;;30204:4;17870:5;29605:14;-1:-1;17909:260;17934:6;17931:1;17928:13;17909:260;;;17995:13;;18381:37;;17322:14;;;;30010;;;;17956:1;17949:9;17909:260;;;-1:-1;18175:10;;17625:566;-1:-1;;;;;17625:566::o;20526:387::-;18381:37;;;-1:-1;;;;;;31032:78;20777:2;20768:12;;18676:56;20877:11;;;20668:245::o;20920:291::-;;32321:6;32316:3;32311;32298:30;32359:16;;32352:27;;;32359:16;21064:147;-1:-1;21064:147::o;21218:659::-;-1:-1;;;20051:87;;20036:1;20157:11;;18381:37;;;;21729:12;;;18381:37;21840:12;;;21463:414::o;21884:222::-;-1:-1;;;;;31415:54;;;;17421:37;;22011:2;21996:18;;21982:124::o;22113:370::-;;22290:2;22311:17;22304:47;22365:108;22290:2;22279:9;22275:18;22459:6;22365:108;:::i;22490:629::-;;22745:2;22766:17;22759:47;22820:108;22745:2;22734:9;22730:18;22914:6;22820:108;:::i;:::-;22976:9;22970:4;22966:20;22961:2;22950:9;22946:18;22939:48;23001:108;23104:4;23095:6;23001:108;:::i;23126:210::-;30866:13;;30859:21;18264:34;;23247:2;23232:18;;23218:118::o;23343:432::-;30866:13;;30859:21;18264:34;;23678:2;23663:18;;18381:37;;;;23761:2;23746:18;;18381:37;23520:2;23505:18;;23491:284::o;23782:222::-;18381:37;;;23909:2;23894:18;;23880:124::o;24011:444::-;18381:37;;;-1:-1;;;;;31415:54;;;24358:2;24343:18;;17421:37;31415:54;24441:2;24426:18;;17421:37;24194:2;24179:18;;24165:290::o;24462:780::-;18381:37;;;-1:-1;;;;;31415:54;;;24894:2;24879:18;;17421:37;31415:54;;;;24977:2;24962:18;;17421:37;25060:2;25045:18;;18381:37;25143:3;25128:19;;18381:37;;;;-1:-1;25212:19;;18381:37;24729:3;24714:19;;24700:542::o;25249:668::-;18381:37;;;25653:2;25638:18;;18381:37;;;;25736:2;25721:18;;18381:37;;;;25819:2;25804:18;;18381:37;-1:-1;;;;;31415:54;25902:3;25887:19;;17421:37;-1:-1;25473:19;;25459:458::o;25924:548::-;18381:37;;;31631:4;31620:16;;;;26292:2;26277:18;;20479:35;26375:2;26360:18;;18381:37;26458:2;26443:18;;18381:37;26131:3;26116:19;;26102:370::o;27007:310::-;;27154:2;;27175:17;27168:47;19566:5;29751:12;30167:6;27154:2;27143:9;27139:18;30155:19;-1:-1;32466:101;32480:6;32477:1;32474:13;32466:101;;;32547:11;;;;;32541:18;32528:11;;;30195:14;32528:11;32521:39;32495:10;;32466:101;;;32582:6;32579:1;32576:13;32573:2;;;-1:-1;30195:14;32638:6;27143:9;32629:16;;32622:27;32573:2;-1:-1;29400:9;32899:14;-1:-1;;32895:28;19724:39;;;;30195:14;19724:39;;27125:192;-1:-1;;;27125:192::o;27553:481::-;;18411:5;18388:3;18381:37;27758:2;27876;27865:9;27861:18;27854:48;27916:108;27758:2;27747:9;27743:18;28010:6;27916:108;:::i;28041:214::-;31631:4;31620:16;;;;20479:35;;28164:2;28149:18;;28135:120::o;28262:256::-;28324:2;28318:9;28350:17;;;28425:18;28410:34;;28446:22;;;28407:62;28404:2;;;28482:1;;28472:12;28404:2;28324;28491:22;28302:216;;-1:-1;28302:216::o;28525:319::-;;28699:18;28691:6;28688:30;28685:2;;;-1:-1;;28721:12;28685:2;-1:-1;28766:4;28754:17;;;28819:15;;28622:222::o;32936:117::-;-1:-1;;;;;31415:54;;32995:35;;32985:2;;33044:1;;33034:12;33060:111;33141:5;30866:13;30859:21;33119:5;33116:32;33106:2;;33162:1;;33152:12;33742:107;33824:1;33817:5;33814:12;33804:2;;33840:1;;33830:12
Swarm Source
ipfs://a2c3b62e0bc50507598395387e1557612d7ad59e817ddae4d5279907402fedb4
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.