Contract 0x974d3ff709d84ba44cde3257c0b5b0b14c081ce9 4

Contract Overview

Balance:
0 FTM
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xe959082928441767dd0c393f472be7e9d48368270ce805909b3f584aab74e9270x6101806017204992021-09-13 8:03:55558 days 15 hrs ago0x4fbe899d37fb7514adf2f41b0630e018ec275a0c IN  Create: Vault0 FTM0.009115127032
[ Download CSV Export 
Latest 2 internal transactions
Parent Txn Hash Block From To Value
0xe959082928441767dd0c393f472be7e9d48368270ce805909b3f584aab74e92717204992021-09-13 8:03:55558 days 15 hrs ago 0x974d3ff709d84ba44cde3257c0b5b0b14c081ce9  Contract Creation0 FTM
0xe959082928441767dd0c393f472be7e9d48368270ce805909b3f584aab74e92717204992021-09-13 8:03:55558 days 15 hrs ago 0x4fbe899d37fb7514adf2f41b0630e018ec275a0c  Contract Creation0 FTM
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Vault

Compiler Version
v0.7.1+commit.f4a555be

Optimization Enabled:
Yes with 1500 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 45 : Vault.sol
// 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 "./interfaces/IAuthorizer.sol";
import "./interfaces/IWETH.sol";

import "./VaultAuthorization.sol";
import "./FlashLoans.sol";
import "./Swaps.sol";

/**
 * @dev The `Vault` is Balancer V2's core contract. A single instance of it exists for the entire network, and it is the
 * entity used to interact with Pools by Liquidity Providers who join and exit them, Traders who swap, and Asset
 * Managers who withdraw and deposit tokens.
 *
 * The `Vault`'s source code is split among a number of sub-contracts, with the goal of improving readability and making
 * understanding the system easier. Most sub-contracts have been marked as `abstract` to explicitly indicate that only
 * the full `Vault` is meant to be deployed.
 *
 * Roughly speaking, these are the contents of each sub-contract:
 *
 *  - `AssetManagers`: Pool token Asset Manager registry, and Asset Manager interactions.
 *  - `Fees`: set and compute protocol fees.
 *  - `FlashLoans`: flash loan transfers and fees.
 *  - `PoolBalances`: Pool joins and exits.
 *  - `PoolRegistry`: Pool registration, ID management, and basic queries.
 *  - `PoolTokens`: Pool token registration and registration, and balance queries.
 *  - `Swaps`: Pool swaps.
 *  - `UserBalance`: manage user balances (Internal Balance operations and external balance transfers)
 *  - `VaultAuthorization`: access control, relayers and signature validation.
 *
 * Additionally, the different Pool specializations are handled by the `GeneralPoolsBalance`,
 * `MinimalSwapInfoPoolsBalance` and `TwoTokenPoolsBalance` sub-contracts, which in turn make use of the
 * `BalanceAllocation` library.
 *
 * The most important goal of the `Vault` is to make token swaps use as little gas as possible. This is reflected in a
 * multitude of design decisions, from minor things like the format used to store Pool IDs, to major features such as
 * the different Pool specialization settings.
 *
 * Finally, the large number of tasks carried out by the Vault means its bytecode is very large, close to exceeding
 * the contract size limit imposed by EIP 170 (https://eips.ethereum.org/EIPS/eip-170). Manual tuning of the source code
 * was required to improve code generation and bring the bytecode size below this limit. This includes extensive
 * utilization of `internal` functions (particularly inside modifiers), usage of named return arguments, dedicated
 * storage access methods, dynamic revert reason generation, and usage of inline assembly, to name a few.
 */
contract Vault is VaultAuthorization, FlashLoans, Swaps {
    constructor(
        IAuthorizer authorizer,
        IWETH weth,
        uint256 pauseWindowDuration,
        uint256 bufferPeriodDuration
    ) VaultAuthorization(authorizer) AssetHelpers(weth) TemporarilyPausable(pauseWindowDuration, bufferPeriodDuration) {
        // solhint-disable-previous-line no-empty-blocks
    }

    function setPaused(bool paused) external override nonReentrant authenticate {
        _setPaused(paused);
    }

    // solhint-disable-next-line func-name-mixedcase
    function WETH() external view override returns (IWETH) {
        return _WETH();
    }
}

File 2 of 45 : IAuthorizer.sol
// 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);
}

File 3 of 45 : IWETH.sol
// 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;
}

File 4 of 45 : VaultAuthorization.sol
// 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/helpers/BalancerErrors.sol";
import "../lib/helpers/Authentication.sol";
import "../lib/helpers/TemporarilyPausable.sol";
import "../lib/helpers/BalancerErrors.sol";
import "../lib/helpers/SignaturesValidator.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";

import "./interfaces/IVault.sol";
import "./interfaces/IAuthorizer.sol";

/**
 * @dev Manages access control of Vault permissioned functions by relying on the Authorizer and signature validation.
 *
 * Additionally handles relayer access and approval.
 */
abstract contract VaultAuthorization is
    IVault,
    ReentrancyGuard,
    Authentication,
    SignaturesValidator,
    TemporarilyPausable
{
    // Ideally, we'd store the type hashes as immutable state variables to avoid computing the hash at runtime, but
    // unfortunately immutable variables cannot be used in assembly, so we just keep the precomputed hashes instead.

    // _JOIN_TYPE_HASH = keccak256("JoinPool(bytes calldata,address sender,uint256 nonce,uint256 deadline)");
    bytes32 private constant _JOIN_TYPE_HASH = 0x3f7b71252bd19113ff48c19c6e004a9bcfcca320a0d74d58e85877cbd7dcae58;

    // _EXIT_TYPE_HASH = keccak256("ExitPool(bytes calldata,address sender,uint256 nonce,uint256 deadline)");
    bytes32 private constant _EXIT_TYPE_HASH = 0x8bbc57f66ea936902f50a71ce12b92c43f3c5340bb40c27c4e90ab84eeae3353;

    // _SWAP_TYPE_HASH = keccak256("Swap(bytes calldata,address sender,uint256 nonce,uint256 deadline)");
    bytes32 private constant _SWAP_TYPE_HASH = 0xe192dcbc143b1e244ad73b813fd3c097b832ad260a157340b4e5e5beda067abe;

    // _BATCH_SWAP_TYPE_HASH = keccak256("BatchSwap(bytes calldata,address sender,uint256 nonce,uint256 deadline)");
    bytes32 private constant _BATCH_SWAP_TYPE_HASH = 0x9bfc43a4d98313c6766986ffd7c916c7481566d9f224c6819af0a53388aced3a;

    // _SET_RELAYER_TYPE_HASH =
    //     keccak256("SetRelayerApproval(bytes calldata,address sender,uint256 nonce,uint256 deadline)");
    bytes32
        private constant _SET_RELAYER_TYPE_HASH = 0xa3f865aa351e51cfeb40f5178d1564bb629fe9030b83caf6361d1baaf5b90b5a;

    IAuthorizer private _authorizer;
    mapping(address => mapping(address => bool)) private _approvedRelayers;

    /**
     * @dev Reverts unless `user` is the caller, or the caller is approved by the Authorizer to call this function (that
     * is, it is a relayer for that function), and either:
     *  a) `user` approved the caller as a relayer (via `setRelayerApproval`), or
     *  b) a valid signature from them was appended to the calldata.
     *
     * Should only be applied to external functions.
     */
    modifier authenticateFor(address user) {
        _authenticateFor(user);
        _;
    }

    constructor(IAuthorizer authorizer)
        // The Vault is a singleton, so it simply uses its own address to disambiguate action identifiers.
        Authentication(bytes32(uint256(address(this))))
        SignaturesValidator("Balancer V2 Vault")
    {
        _setAuthorizer(authorizer);
    }

    function setAuthorizer(IAuthorizer newAuthorizer) external override nonReentrant authenticate {
        _setAuthorizer(newAuthorizer);
    }

    function _setAuthorizer(IAuthorizer newAuthorizer) private {
        emit AuthorizerChanged(newAuthorizer);
        _authorizer = newAuthorizer;
    }

    function getAuthorizer() external view override returns (IAuthorizer) {
        return _authorizer;
    }

    function setRelayerApproval(
        address sender,
        address relayer,
        bool approved
    ) external override nonReentrant whenNotPaused authenticateFor(sender) {
        _approvedRelayers[sender][relayer] = approved;
        emit RelayerApprovalChanged(relayer, sender, approved);
    }

    function hasApprovedRelayer(address user, address relayer) external view override returns (bool) {
        return _hasApprovedRelayer(user, relayer);
    }

    /**
     * @dev Reverts unless `user` is the caller, or the caller is approved by the Authorizer to call the entry point
     * function (that is, it is a relayer for that function) and either:
     *  a) `user` approved the caller as a relayer (via `setRelayerApproval`), or
     *  b) a valid signature from them was appended to the calldata.
     */
    function _authenticateFor(address user) internal {
        if (msg.sender != user) {
            // In this context, 'permission to call a function' means 'being a relayer for a function'.
            _authenticateCaller();

            // Being a relayer is not sufficient: `user` must have also approved the caller either via
            // `setRelayerApproval`, or by providing a signature appended to the calldata.
            if (!_hasApprovedRelayer(user, msg.sender)) {
                _validateSignature(user, Errors.USER_DOESNT_ALLOW_RELAYER);
            }
        }
    }

    /**
     * @dev Returns true if `user` approved `relayer` to act as a relayer for them.
     */
    function _hasApprovedRelayer(address user, address relayer) internal view returns (bool) {
        return _approvedRelayers[user][relayer];
    }

    function _canPerform(bytes32 actionId, address user) internal view override returns (bool) {
        // Access control is delegated to the Authorizer.
        return _authorizer.canPerform(actionId, user, address(this));
    }

    function _typeHash() internal pure override returns (bytes32 hash) {
        // This is a simple switch-case statement, trivially written in Solidity by chaining else-if statements, but the
        // assembly implementation results in much denser bytecode.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            // The function selector is located at the first 4 bytes of calldata. We copy the first full calldata
            // 256 word, and then perform a logical shift to the right, moving the selector to the least significant
            // 4 bytes.
            let selector := shr(224, calldataload(0))

            // With the selector in the least significant 4 bytes, we can use 4 byte literals with leading zeros,
            // resulting in dense bytecode (PUSH4 opcodes).
            switch selector
                case 0xb95cac28 {
                    hash := _JOIN_TYPE_HASH
                }
                case 0x8bdb3913 {
                    hash := _EXIT_TYPE_HASH
                }
                case 0x52bbbe29 {
                    hash := _SWAP_TYPE_HASH
                }
                case 0x945bcec9 {
                    hash := _BATCH_SWAP_TYPE_HASH
                }
                case 0xfa6e671d {
                    hash := _SET_RELAYER_TYPE_HASH
                }
                default {
                    hash := 0x0000000000000000000000000000000000000000000000000000000000000000
                }
        }
    }
}

File 5 of 45 : FlashLoans.sol
// 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/>.

// This flash loan provider was based on the Aave protocol's open source
// implementation and terminology and interfaces are intentionally kept
// similar

pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../lib/helpers/BalancerErrors.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";
import "../lib/openzeppelin/SafeERC20.sol";

import "./Fees.sol";
import "./interfaces/IFlashLoanRecipient.sol";

/**
 * @dev Handles Flash Loans through the Vault. Calls the `receiveFlashLoan` hook on the flash loan recipient
 * contract, which implements the `IFlashLoanRecipient` interface.
 */
abstract contract FlashLoans is Fees, ReentrancyGuard, TemporarilyPausable {
    using SafeERC20 for IERC20;

    function flashLoan(
        IFlashLoanRecipient recipient,
        IERC20[] memory tokens,
        uint256[] memory amounts,
        bytes memory userData
    ) external override nonReentrant whenNotPaused {
        InputHelpers.ensureInputLengthMatch(tokens.length, amounts.length);

        uint256[] memory feeAmounts = new uint256[](tokens.length);
        uint256[] memory preLoanBalances = new uint256[](tokens.length);

        // Used to ensure `tokens` is sorted in ascending order, which ensures token uniqueness.
        IERC20 previousToken = IERC20(0);

        for (uint256 i = 0; i < tokens.length; ++i) {
            IERC20 token = tokens[i];
            uint256 amount = amounts[i];

            _require(token > previousToken, token == IERC20(0) ? Errors.ZERO_TOKEN : Errors.UNSORTED_TOKENS);
            previousToken = token;

            preLoanBalances[i] = token.balanceOf(address(this));
            feeAmounts[i] = _calculateFlashLoanFeeAmount(amount);

            _require(preLoanBalances[i] >= amount, Errors.INSUFFICIENT_FLASH_LOAN_BALANCE);
            token.safeTransfer(address(recipient), amount);
        }

        recipient.receiveFlashLoan(tokens, amounts, feeAmounts, userData);

        for (uint256 i = 0; i < tokens.length; ++i) {
            IERC20 token = tokens[i];
            uint256 preLoanBalance = preLoanBalances[i];

            // Checking for loan repayment first (without accounting for fees) makes for simpler debugging, and results
            // in more accurate revert reasons if the flash loan protocol fee percentage is zero.
            uint256 postLoanBalance = token.balanceOf(address(this));
            _require(postLoanBalance >= preLoanBalance, Errors.INVALID_POST_LOAN_BALANCE);

            // No need for checked arithmetic since we know the loan was fully repaid.
            uint256 receivedFeeAmount = postLoanBalance - preLoanBalance;
            _require(receivedFeeAmount >= feeAmounts[i], Errors.INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT);

            _payFeeAmount(token, receivedFeeAmount);
            emit FlashLoan(recipient, token, amounts[i], receivedFeeAmount);
        }
    }
}

File 6 of 45 : Swaps.sol
// 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/Math.sol";
import "../lib/helpers/BalancerErrors.sol";
import "../lib/helpers/InputHelpers.sol";
import "../lib/openzeppelin/EnumerableMap.sol";
import "../lib/openzeppelin/EnumerableSet.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";
import "../lib/openzeppelin/SafeCast.sol";
import "../lib/openzeppelin/SafeERC20.sol";

import "./PoolBalances.sol";
import "./interfaces/IPoolSwapStructs.sol";
import "./interfaces/IGeneralPool.sol";
import "./interfaces/IMinimalSwapInfoPool.sol";
import "./balances/BalanceAllocation.sol";

/**
 * Implements the Vault's high-level swap functionality.
 *
 * Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. They need not trust the Pool
 * contracts to do this: all security checks are made by the Vault.
 *
 * 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.
 */
abstract contract Swaps is ReentrancyGuard, PoolBalances {
    using SafeERC20 for IERC20;
    using EnumerableSet for EnumerableSet.AddressSet;
    using EnumerableMap for EnumerableMap.IERC20ToBytes32Map;

    using Math for int256;
    using Math for uint256;
    using SafeCast for uint256;
    using BalanceAllocation for bytes32;

    function swap(
        SingleSwap memory singleSwap,
        FundManagement memory funds,
        uint256 limit,
        uint256 deadline
    )
        external
        payable
        override
        nonReentrant
        whenNotPaused
        authenticateFor(funds.sender)
        returns (uint256 amountCalculated)
    {
        // The deadline is timestamp-based: it should not be relied upon for sub-minute accuracy.
        // solhint-disable-next-line not-rely-on-time
        _require(block.timestamp <= deadline, Errors.SWAP_DEADLINE);

        // This revert reason is for consistency with `batchSwap`: an equivalent `swap` performed using that function
        // would result in this error.
        _require(singleSwap.amount > 0, Errors.UNKNOWN_AMOUNT_IN_FIRST_SWAP);

        IERC20 tokenIn = _translateToIERC20(singleSwap.assetIn);
        IERC20 tokenOut = _translateToIERC20(singleSwap.assetOut);
        _require(tokenIn != tokenOut, Errors.CANNOT_SWAP_SAME_TOKEN);

        // Initializing each struct field one-by-one uses less gas than setting all at once.
        IPoolSwapStructs.SwapRequest memory poolRequest;
        poolRequest.poolId = singleSwap.poolId;
        poolRequest.kind = singleSwap.kind;
        poolRequest.tokenIn = tokenIn;
        poolRequest.tokenOut = tokenOut;
        poolRequest.amount = singleSwap.amount;
        poolRequest.userData = singleSwap.userData;
        poolRequest.from = funds.sender;
        poolRequest.to = funds.recipient;
        // The lastChangeBlock field is left uninitialized.

        uint256 amountIn;
        uint256 amountOut;

        (amountCalculated, amountIn, amountOut) = _swapWithPool(poolRequest);
        _require(singleSwap.kind == SwapKind.GIVEN_IN ? amountOut >= limit : amountIn <= limit, Errors.SWAP_LIMIT);

        _receiveAsset(singleSwap.assetIn, amountIn, funds.sender, funds.fromInternalBalance);
        _sendAsset(singleSwap.assetOut, amountOut, funds.recipient, funds.toInternalBalance);

        // If the asset in is ETH, then `amountIn` ETH was wrapped into WETH.
        _handleRemainingEth(_isETH(singleSwap.assetIn) ? amountIn : 0);
    }

    function batchSwap(
        SwapKind kind,
        BatchSwapStep[] memory swaps,
        IAsset[] memory assets,
        FundManagement memory funds,
        int256[] memory limits,
        uint256 deadline
    )
        external
        payable
        override
        nonReentrant
        whenNotPaused
        authenticateFor(funds.sender)
        returns (int256[] memory assetDeltas)
    {
        // The deadline is timestamp-based: it should not be relied upon for sub-minute accuracy.
        // solhint-disable-next-line not-rely-on-time
        _require(block.timestamp <= deadline, Errors.SWAP_DEADLINE);

        InputHelpers.ensureInputLengthMatch(assets.length, limits.length);

        // Perform the swaps, updating the Pool token balances and computing the net Vault asset deltas.
        assetDeltas = _swapWithPools(swaps, assets, funds, kind);

        // Process asset deltas, by either transferring assets from the sender (for positive deltas) or to the recipient
        // (for negative deltas).
        uint256 wrappedEth = 0;
        for (uint256 i = 0; i < assets.length; ++i) {
            IAsset asset = assets[i];
            int256 delta = assetDeltas[i];
            _require(delta <= limits[i], Errors.SWAP_LIMIT);

            if (delta > 0) {
                uint256 toReceive = uint256(delta);
                _receiveAsset(asset, toReceive, funds.sender, funds.fromInternalBalance);

                if (_isETH(asset)) {
                    wrappedEth = wrappedEth.add(toReceive);
                }
            } else if (delta < 0) {
                uint256 toSend = uint256(-delta);
                _sendAsset(asset, toSend, funds.recipient, funds.toInternalBalance);
            }
        }

        // Handle any used and remaining ETH.
        _handleRemainingEth(wrappedEth);
    }

    // For `_swapWithPools` to handle both 'given in' and 'given out' swaps, it internally tracks the 'given' amount
    // (supplied by the caller), and the 'calculated' amount (returned by the Pool in response to the swap request).

    /**
     * @dev Given the two swap tokens and the swap kind, returns which one is the 'given' token (the token whose
     * amount is supplied by the caller).
     */
    function _tokenGiven(
        SwapKind kind,
        IERC20 tokenIn,
        IERC20 tokenOut
    ) private pure returns (IERC20) {
        return kind == SwapKind.GIVEN_IN ? tokenIn : tokenOut;
    }

    /**
     * @dev Given the two swap tokens and the swap kind, returns which one is the 'calculated' token (the token whose
     * amount is calculated by the Pool).
     */
    function _tokenCalculated(
        SwapKind kind,
        IERC20 tokenIn,
        IERC20 tokenOut
    ) private pure returns (IERC20) {
        return kind == SwapKind.GIVEN_IN ? tokenOut : tokenIn;
    }

    /**
     * @dev Returns an ordered pair (amountIn, amountOut) given the 'given' and 'calculated' amounts, and the swap kind.
     */
    function _getAmounts(
        SwapKind kind,
        uint256 amountGiven,
        uint256 amountCalculated
    ) private pure returns (uint256 amountIn, uint256 amountOut) {
        if (kind == SwapKind.GIVEN_IN) {
            (amountIn, amountOut) = (amountGiven, amountCalculated);
        } else {
            // SwapKind.GIVEN_OUT
            (amountIn, amountOut) = (amountCalculated, amountGiven);
        }
    }

    /**
     * @dev Performs all `swaps`, calling swap hooks on the Pool contracts and updating their balances. Does not cause
     * any transfer of tokens - instead it returns the net Vault token deltas: positive if the Vault should receive
     * tokens, and negative if it should send them.
     */
    function _swapWithPools(
        BatchSwapStep[] memory swaps,
        IAsset[] memory assets,
        FundManagement memory funds,
        SwapKind kind
    ) private returns (int256[] memory assetDeltas) {
        assetDeltas = new int256[](assets.length);

        // These variables could be declared inside the loop, but that causes the compiler to allocate memory on each
        // loop iteration, increasing gas costs.
        BatchSwapStep memory batchSwapStep;
        IPoolSwapStructs.SwapRequest memory poolRequest;

        // These store data about the previous swap here to implement multihop logic across swaps.
        IERC20 previousTokenCalculated;
        uint256 previousAmountCalculated;

        for (uint256 i = 0; i < swaps.length; ++i) {
            batchSwapStep = swaps[i];

            bool withinBounds = batchSwapStep.assetInIndex < assets.length &&
                batchSwapStep.assetOutIndex < assets.length;
            _require(withinBounds, Errors.OUT_OF_BOUNDS);

            IERC20 tokenIn = _translateToIERC20(assets[batchSwapStep.assetInIndex]);
            IERC20 tokenOut = _translateToIERC20(assets[batchSwapStep.assetOutIndex]);
            _require(tokenIn != tokenOut, Errors.CANNOT_SWAP_SAME_TOKEN);

            // Sentinel value for multihop logic
            if (batchSwapStep.amount == 0) {
                // When the amount given is zero, we use the calculated amount for the previous swap, as long as the
                // current swap's given token is the previous calculated token. This makes it possible to swap a
                // given amount of token A for token B, and then use the resulting token B amount to swap for token C.
                _require(i > 0, Errors.UNKNOWN_AMOUNT_IN_FIRST_SWAP);
                bool usingPreviousToken = previousTokenCalculated == _tokenGiven(kind, tokenIn, tokenOut);
                _require(usingPreviousToken, Errors.MALCONSTRUCTED_MULTIHOP_SWAP);
                batchSwapStep.amount = previousAmountCalculated;
            }

            // Initializing each struct field one-by-one uses less gas than setting all at once
            poolRequest.poolId = batchSwapStep.poolId;
            poolRequest.kind = kind;
            poolRequest.tokenIn = tokenIn;
            poolRequest.tokenOut = tokenOut;
            poolRequest.amount = batchSwapStep.amount;
            poolRequest.userData = batchSwapStep.userData;
            poolRequest.from = funds.sender;
            poolRequest.to = funds.recipient;
            // The lastChangeBlock field is left uninitialized

            uint256 amountIn;
            uint256 amountOut;
            (previousAmountCalculated, amountIn, amountOut) = _swapWithPool(poolRequest);

            previousTokenCalculated = _tokenCalculated(kind, tokenIn, tokenOut);

            // Accumulate Vault deltas across swaps
            assetDeltas[batchSwapStep.assetInIndex] = assetDeltas[batchSwapStep.assetInIndex].add(amountIn.toInt256());
            assetDeltas[batchSwapStep.assetOutIndex] = assetDeltas[batchSwapStep.assetOutIndex].sub(
                amountOut.toInt256()
            );
        }
    }

    /**
     * @dev Performs a swap according to the parameters specified in `request`, calling the Pool's contract hook and
     * updating the Pool's balance.
     *
     * Returns the amount of tokens going into or out of the Vault as a result of this swap, depending on the swap kind.
     */
    function _swapWithPool(IPoolSwapStructs.SwapRequest memory request)
        private
        returns (
            uint256 amountCalculated,
            uint256 amountIn,
            uint256 amountOut
        )
    {
        // Get the calculated amount from the Pool and update its balances
        address pool = _getPoolAddress(request.poolId);
        PoolSpecialization specialization = _getPoolSpecialization(request.poolId);

        if (specialization == PoolSpecialization.TWO_TOKEN) {
            amountCalculated = _processTwoTokenPoolSwapRequest(request, IMinimalSwapInfoPool(pool));
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            amountCalculated = _processMinimalSwapInfoPoolSwapRequest(request, IMinimalSwapInfoPool(pool));
        } else {
            // PoolSpecialization.GENERAL
            amountCalculated = _processGeneralPoolSwapRequest(request, IGeneralPool(pool));
        }

        (amountIn, amountOut) = _getAmounts(request.kind, request.amount, amountCalculated);
        emit Swap(request.poolId, request.tokenIn, request.tokenOut, amountIn, amountOut);
    }

    function _processTwoTokenPoolSwapRequest(IPoolSwapStructs.SwapRequest memory request, IMinimalSwapInfoPool pool)
        private
        returns (uint256 amountCalculated)
    {
        // For gas efficiency reasons, this function uses low-level knowledge of how Two Token Pool balances are
        // stored internally, instead of using getters and setters for all operations.

        (
            bytes32 tokenABalance,
            bytes32 tokenBBalance,
            TwoTokenPoolBalances storage poolBalances
        ) = _getTwoTokenPoolSharedBalances(request.poolId, request.tokenIn, request.tokenOut);

        // We have the two Pool balances, but we don't know which one is 'token in' or 'token out'.
        bytes32 tokenInBalance;
        bytes32 tokenOutBalance;

        // In Two Token Pools, token A has a smaller address than token B
        if (request.tokenIn < request.tokenOut) {
            // in is A, out is B
            tokenInBalance = tokenABalance;
            tokenOutBalance = tokenBBalance;
        } else {
            // in is B, out is A
            tokenOutBalance = tokenABalance;
            tokenInBalance = tokenBBalance;
        }

        // Perform the swap request and compute the new balances for 'token in' and 'token out' after the swap
        (tokenInBalance, tokenOutBalance, amountCalculated) = _callMinimalSwapInfoPoolOnSwapHook(
            request,
            pool,
            tokenInBalance,
            tokenOutBalance
        );

        // We check the token ordering again to create the new shared cash packed struct
        poolBalances.sharedCash = request.tokenIn < request.tokenOut
            ? BalanceAllocation.toSharedCash(tokenInBalance, tokenOutBalance) // in is A, out is B
            : BalanceAllocation.toSharedCash(tokenOutBalance, tokenInBalance); // in is B, out is A
    }

    function _processMinimalSwapInfoPoolSwapRequest(
        IPoolSwapStructs.SwapRequest memory request,
        IMinimalSwapInfoPool pool
    ) private returns (uint256 amountCalculated) {
        bytes32 tokenInBalance = _getMinimalSwapInfoPoolBalance(request.poolId, request.tokenIn);
        bytes32 tokenOutBalance = _getMinimalSwapInfoPoolBalance(request.poolId, request.tokenOut);

        // Perform the swap request and compute the new balances for 'token in' and 'token out' after the swap
        (tokenInBalance, tokenOutBalance, amountCalculated) = _callMinimalSwapInfoPoolOnSwapHook(
            request,
            pool,
            tokenInBalance,
            tokenOutBalance
        );

        _minimalSwapInfoPoolsBalances[request.poolId][request.tokenIn] = tokenInBalance;
        _minimalSwapInfoPoolsBalances[request.poolId][request.tokenOut] = tokenOutBalance;
    }

    /**
     * @dev Calls the onSwap hook for a Pool that implements IMinimalSwapInfoPool: both Minimal Swap Info and Two Token
     * Pools do this.
     */
    function _callMinimalSwapInfoPoolOnSwapHook(
        IPoolSwapStructs.SwapRequest memory request,
        IMinimalSwapInfoPool pool,
        bytes32 tokenInBalance,
        bytes32 tokenOutBalance
    )
        internal
        returns (
            bytes32 newTokenInBalance,
            bytes32 newTokenOutBalance,
            uint256 amountCalculated
        )
    {
        uint256 tokenInTotal = tokenInBalance.total();
        uint256 tokenOutTotal = tokenOutBalance.total();
        request.lastChangeBlock = Math.max(tokenInBalance.lastChangeBlock(), tokenOutBalance.lastChangeBlock());

        // Perform the swap request callback, and compute the new balances for 'token in' and 'token out' after the swap
        amountCalculated = pool.onSwap(request, tokenInTotal, tokenOutTotal);
        (uint256 amountIn, uint256 amountOut) = _getAmounts(request.kind, request.amount, amountCalculated);

        newTokenInBalance = tokenInBalance.increaseCash(amountIn);
        newTokenOutBalance = tokenOutBalance.decreaseCash(amountOut);
    }

    function _processGeneralPoolSwapRequest(IPoolSwapStructs.SwapRequest memory request, IGeneralPool pool)
        private
        returns (uint256 amountCalculated)
    {
        bytes32 tokenInBalance;
        bytes32 tokenOutBalance;

        // We access both token indexes without checking existence, because we will do it manually immediately after.
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[request.poolId];
        uint256 indexIn = poolBalances.unchecked_indexOf(request.tokenIn);
        uint256 indexOut = poolBalances.unchecked_indexOf(request.tokenOut);

        if (indexIn == 0 || indexOut == 0) {
            // The tokens might not be registered because the Pool itself is not registered. We check this to provide a
            // more accurate revert reason.
            _ensureRegisteredPool(request.poolId);
            _revert(Errors.TOKEN_NOT_REGISTERED);
        }

        // EnumerableMap stores indices *plus one* to use the zero index as a sentinel value - because these are valid,
        // we can undo this.
        indexIn -= 1;
        indexOut -= 1;

        uint256 tokenAmount = poolBalances.length();
        uint256[] memory currentBalances = new uint256[](tokenAmount);

        request.lastChangeBlock = 0;
        for (uint256 i = 0; i < tokenAmount; i++) {
            // Because the iteration is bounded by `tokenAmount`, and no tokens are registered or deregistered here, we
            // know `i` is a valid token index and can use `unchecked_valueAt` to save storage reads.
            bytes32 balance = poolBalances.unchecked_valueAt(i);

            currentBalances[i] = balance.total();
            request.lastChangeBlock = Math.max(request.lastChangeBlock, balance.lastChangeBlock());

            if (i == indexIn) {
                tokenInBalance = balance;
            } else if (i == indexOut) {
                tokenOutBalance = balance;
            }
        }

        // Perform the swap request callback and compute the new balances for 'token in' and 'token out' after the swap
        amountCalculated = pool.onSwap(request, currentBalances, indexIn, indexOut);
        (uint256 amountIn, uint256 amountOut) = _getAmounts(request.kind, request.amount, amountCalculated);
        tokenInBalance = tokenInBalance.increaseCash(amountIn);
        tokenOutBalance = tokenOutBalance.decreaseCash(amountOut);

        // Because no tokens were registered or deregistered between now or when we retrieved the indexes for
        // 'token in' and 'token out', we can use `unchecked_setAt` to save storage reads.
        poolBalances.unchecked_setAt(indexIn, tokenInBalance);
        poolBalances.unchecked_setAt(indexOut, tokenOutBalance);
    }

    // This function is not marked as `nonReentrant` because the underlying mechanism relies on reentrancy
    function queryBatchSwap(
        SwapKind kind,
        BatchSwapStep[] memory swaps,
        IAsset[] memory assets,
        FundManagement memory funds
    ) external override returns (int256[] memory) {
        // In order to accurately 'simulate' swaps, this function actually does perform the swaps, including calling the
        // Pool hooks and updating balances in storage. However, once it computes the final Vault Deltas, it
        // reverts unconditionally, returning this array as the revert data.
        //
        // By wrapping this reverting call, we can decode the deltas 'returned' and return them as a normal Solidity
        // function would. The only caveat is the function becomes non-view, but off-chain clients can still call it
        // via eth_call to get the expected result.
        //
        // This technique was inspired by the work from the Gnosis team in the Gnosis Safe contract:
        // https://github.com/gnosis/safe-contracts/blob/v1.2.0/contracts/GnosisSafe.sol#L265
        //
        // Most of this function is implemented using inline assembly, as the actual work it needs to do is not
        // significant, and Solidity is not particularly well-suited to generate this behavior, resulting in a large
        // amount of generated bytecode.

        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 actual asset deltas 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, 0xfa61cc1200000000000000000000000000000000000000000000000000000000), 0) {
                            returndatacopy(0, 0, returndatasize())
                            revert(0, returndatasize())
                        }

                        // The returndata contains the signature, followed by the raw memory representation of an array:
                        // length + data. We need to return an ABI-encoded representation of this array.
                        // An ABI-encoded array contains an additional field when compared to its raw memory
                        // representation: an offset to the location of the length. The offset itself is 32 bytes long,
                        // so the smallest value we  can use is 32 for the data to be located immediately after it.
                        mstore(0, 32)

                        // We now copy the raw memory array from returndata into memory. Since the offset takes up 32
                        // bytes, we start copying at address 0x20. We also get rid of the error signature, which takes
                        // the first four bytes of returndata.
                        let size := sub(returndatasize(), 0x04)
                        returndatacopy(0x20, 0x04, size)

                        // We finally return the ABI-encoded array, which has a total length equal to that of the array
                        // (returndata), plus the 32 bytes for the offset.
                        return(0, add(size, 32))
                    }
                    default {
                        // This call should always revert, but we fail nonetheless if that didn't happen
                        invalid()
                    }
            }
        } else {
            int256[] memory deltas = _swapWithPools(swaps, assets, funds, kind);

            // solhint-disable-next-line no-inline-assembly
            assembly {
                // We will return a raw representation of the array in memory, which is composed of a 32 byte length,
                // followed by the 32 byte int256 values. Because revert expects a size in bytes, we multiply the array
                // length (stored at `deltas`) by 32.
                let size := mul(mload(deltas), 32)

                // We send one extra value for the error signature "QueryError(int256[])" which is 0xfa61cc12.
                // We store it in the previous slot to the `deltas` array. We know 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.
                mstore(sub(deltas, 0x20), 0x00000000000000000000000000000000000000000000000000000000fa61cc12)
                let start := sub(deltas, 0x04)

                // When copying from `deltas` into returndata, we copy an additional 36 bytes to also return the array's
                // length and the error signature.
                revert(start, add(size, 36))
            }
        }
    }
}

File 7 of 45 : IERC20.sol
// 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);
}

File 8 of 45 : BalancerErrors.sol
// 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;
}

File 9 of 45 : Authentication.sol
// 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);
}

File 10 of 45 : TemporarilyPausable.sol
// 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;
    }
}

File 11 of 45 : SignaturesValidator.sol
// 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 "./ISignaturesValidator.sol";
import "../openzeppelin/EIP712.sol";

/**
 * @dev Utility for signing Solidity function calls.
 *
 * This contract relies on the fact that Solidity contracts can be called with extra calldata, and enables
 * meta-transaction schemes by appending an EIP712 signature of the original calldata at the end.
 *
 * Derived contracts must implement the `_typeHash` function to map function selectors to EIP712 structs.
 */
abstract contract SignaturesValidator is ISignaturesValidator, EIP712 {
    // The appended data consists of a deadline, plus the [v,r,s] signature. For simplicity, we use a full 256 bit slot
    // for each of these values, even if 'v' is typically an 8 bit value.
    uint256 internal constant _EXTRA_CALLDATA_LENGTH = 4 * 32;

    // Replay attack prevention for each user.
    mapping(address => uint256) internal _nextNonce;

    constructor(string memory name) EIP712(name, "1") {
        // solhint-disable-previous-line no-empty-blocks
    }

    function getDomainSeparator() external view override returns (bytes32) {
        return _domainSeparatorV4();
    }

    function getNextNonce(address user) external view override returns (uint256) {
        return _nextNonce[user];
    }

    /**
     * @dev Reverts with `errorCode` unless a valid signature for `user` was appended to the calldata.
     */
    function _validateSignature(address user, uint256 errorCode) internal {
        uint256 nextNonce = _nextNonce[user]++;
        _require(_isSignatureValid(user, nextNonce), errorCode);
    }

    function _isSignatureValid(address user, uint256 nonce) private view returns (bool) {
        uint256 deadline = _deadline();

        // The deadline is timestamp-based: it should not be relied upon for sub-minute accuracy.
        // solhint-disable-next-line not-rely-on-time
        if (deadline < block.timestamp) {
            return false;
        }

        bytes32 typeHash = _typeHash();
        if (typeHash == bytes32(0)) {
            // Prevent accidental signature validation for functions that don't have an associated type hash.
            return false;
        }

        // All type hashes have this format: (bytes calldata, address sender, uint256 nonce, uint256 deadline).
        bytes32 structHash = keccak256(abi.encode(typeHash, keccak256(_calldata()), msg.sender, nonce, deadline));
        bytes32 digest = _hashTypedDataV4(structHash);
        (uint8 v, bytes32 r, bytes32 s) = _signature();

        address recoveredAddress = ecrecover(digest, v, r, s);

        // ecrecover returns the zero address on recover failure, so we need to handle that explicitly.
        return recoveredAddress != address(0) && recoveredAddress == user;
    }

    /**
     * @dev Returns the EIP712 type hash for the current entry point function, which can be identified by its function
     * selector (available as `msg.sig`).
     *
     * The type hash must conform to the following format:
     *  <name>(bytes calldata, address sender, uint256 nonce, uint256 deadline)
     *
     * If 0x00, all signatures will be considered invalid.
     */
    function _typeHash() internal view virtual returns (bytes32);

    /**
     * @dev Extracts the signature deadline from extra calldata.
     *
     * This function returns bogus data if no signature is included.
     */
    function _deadline() internal pure returns (uint256) {
        // The deadline is the first extra argument at the end of the original calldata.
        return uint256(_decodeExtraCalldataWord(0));
    }

    /**
     * @dev Extracts the signature parameters from extra calldata.
     *
     * This function returns bogus data if no signature is included. This is not a security risk, as that data would not
     * be considered a valid signature in the first place.
     */
    function _signature()
        internal
        pure
        returns (
            uint8 v,
            bytes32 r,
            bytes32 s
        )
    {
        // v, r and s are appended after the signature deadline, in that order.
        v = uint8(uint256(_decodeExtraCalldataWord(0x20)));
        r = _decodeExtraCalldataWord(0x40);
        s = _decodeExtraCalldataWord(0x60);
    }

    /**
     * @dev Returns the original calldata, without the extra bytes containing the signature.
     *
     * This function returns bogus data if no signature is included.
     */
    function _calldata() internal pure returns (bytes memory result) {
        result = msg.data; // A calldata to memory assignment results in memory allocation and copy of contents.
        if (result.length > _EXTRA_CALLDATA_LENGTH) {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                // We simply overwrite the array length with the reduced one.
                mstore(result, sub(calldatasize(), _EXTRA_CALLDATA_LENGTH))
            }
        }
    }

    /**
     * @dev Returns a 256 bit word from 'extra' calldata, at some offset from the expected end of the original calldata.
     *
     * This function returns bogus data if no signature is included.
     */
    function _decodeExtraCalldataWord(uint256 offset) private pure returns (bytes32 result) {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            result := calldataload(add(sub(calldatasize(), _EXTRA_CALLDATA_LENGTH), offset))
        }
    }
}

File 12 of 45 : ReentrancyGuard.sol
// 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;
    }
}

File 13 of 45 : IVault.sol
// 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
}

File 14 of 45 : IAuthentication.sol
// 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);
}

File 15 of 45 : ITemporarilyPausable.sol
// 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
        );
}

File 16 of 45 : ISignaturesValidator.sol
// 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);
}

File 17 of 45 : EIP712.sol
// 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()
        }
    }
}

File 18 of 45 : IAsset.sol
// 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
}

File 19 of 45 : IFlashLoanRecipient.sol
// 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;
}

File 20 of 45 : ProtocolFeesCollector.sol
// 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();
    }
}

File 21 of 45 : InputHelpers.sol
// 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;
        }
    }
}

File 22 of 45 : SafeERC20.sol
// 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);
    }
}

File 23 of 45 : Fees.sol
// 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/BalancerErrors.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";
import "../lib/openzeppelin/SafeERC20.sol";

import "./ProtocolFeesCollector.sol";
import "./VaultAuthorization.sol";
import "./interfaces/IVault.sol";

/**
 * @dev To reduce the bytecode size of the Vault, most of the protocol fee logic is not here, but in the
 * ProtocolFeesCollector contract.
 */
abstract contract Fees is IVault {
    using SafeERC20 for IERC20;

    ProtocolFeesCollector private immutable _protocolFeesCollector;

    constructor() {
        _protocolFeesCollector = new ProtocolFeesCollector(IVault(this));
    }

    function getProtocolFeesCollector() public view override returns (ProtocolFeesCollector) {
        return _protocolFeesCollector;
    }

    /**
     * @dev Returns the protocol swap fee percentage.
     */
    function _getProtocolSwapFeePercentage() internal view returns (uint256) {
        return getProtocolFeesCollector().getSwapFeePercentage();
    }

    /**
     * @dev Returns the protocol fee amount to charge for a flash loan of `amount`.
     */
    function _calculateFlashLoanFeeAmount(uint256 amount) internal view returns (uint256) {
        // Fixed point multiplication introduces error: we round up, which means in certain scenarios the charged
        // percentage can be slightly higher than intended.
        uint256 percentage = getProtocolFeesCollector().getFlashLoanFeePercentage();
        return FixedPoint.mulUp(amount, percentage);
    }

    function _payFeeAmount(IERC20 token, uint256 amount) internal {
        if (amount > 0) {
            token.safeTransfer(address(getProtocolFeesCollector()), amount);
        }
    }
}

File 24 of 45 : FixedPoint.sol
// 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;
    }
}

File 25 of 45 : LogExpMath.sol
// 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;
    }
}

File 26 of 45 : Math.sol
// 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;
        }
    }
}

File 27 of 45 : EnumerableMap.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

// Based on the EnumerableMap library from OpenZeppelin contracts, altered to include the following:
//  * a map from IERC20 to bytes32
//  * entries are stored in mappings instead of arrays, reducing implicit storage reads for out-of-bounds checks
//  * unchecked_at and unchecked_valueAt, which allow for more gas efficient data reads in some scenarios
//  * unchecked_indexOf and unchecked_setAt, which allow for more gas efficient data writes in some scenarios
//
// Additionally, the base private functions that work on bytes32 were removed and replaced with a native implementation
// for IERC20 keys, to reduce bytecode size and runtime costs.

// We're using non-standard casing for the unchecked functions to differentiate them, so we need to turn off that rule
// solhint-disable func-name-mixedcase

import "./IERC20.sol";

import "../helpers/BalancerErrors.sol";

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 */
library EnumerableMap {
    // The original OpenZeppelin implementation uses a generic Map type with bytes32 keys: this was replaced with
    // IERC20ToBytes32Map, which uses IERC20 keys natively, resulting in more dense bytecode.

    struct IERC20ToBytes32MapEntry {
        IERC20 _key;
        bytes32 _value;
    }

    struct IERC20ToBytes32Map {
        // Number of entries in the map
        uint256 _length;
        // Storage of map keys and values
        mapping(uint256 => IERC20ToBytes32MapEntry) _entries;
        // Position of the entry defined by a key in the `entries` array, plus 1
        // because index 0 means a key is not in the map.
        mapping(IERC20 => uint256) _indexes;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(
        IERC20ToBytes32Map storage map,
        IERC20 key,
        bytes32 value
    ) internal returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        // Equivalent to !contains(map, key)
        if (keyIndex == 0) {
            uint256 previousLength = map._length;
            map._entries[previousLength] = IERC20ToBytes32MapEntry({ _key: key, _value: value });
            map._length = previousLength + 1;

            // The entry is stored at previousLength, but we add 1 to all indexes
            // and use 0 as a sentinel value
            map._indexes[key] = previousLength + 1;
            return true;
        } else {
            map._entries[keyIndex - 1]._value = value;
            return false;
        }
    }

    /**
     * @dev Updates the value for an entry, given its key's index. The key index can be retrieved via
     * {unchecked_indexOf}, and it should be noted that key indices may change when calling {set} or {remove}. O(1).
     *
     * This function performs one less storage read than {set}, but it should only be used when `index` is known to be
     * within bounds.
     */
    function unchecked_setAt(
        IERC20ToBytes32Map storage map,
        uint256 index,
        bytes32 value
    ) internal {
        map._entries[index]._value = value;
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(IERC20ToBytes32Map storage map, IERC20 key) internal returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        // Equivalent to contains(map, key)
        if (keyIndex != 0) {
            // To delete a key-value pair from the _entries pseudo-array in O(1), we swap the entry to delete with the
            // one at the highest index, and then remove this last entry (sometimes called as 'swap and pop').
            // This modifies the order of the pseudo-array, as noted in {at}.

            uint256 toDeleteIndex = keyIndex - 1;
            uint256 lastIndex = map._length - 1;

            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            IERC20ToBytes32MapEntry storage lastEntry = map._entries[lastIndex];

            // Move the last entry to the index where the entry to delete is
            map._entries[toDeleteIndex] = lastEntry;
            // Update the index for the moved entry
            map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved entry was stored
            delete map._entries[lastIndex];
            map._length = lastIndex;

            // Delete the index for the deleted slot
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(IERC20ToBytes32Map storage map, IERC20 key) internal view returns (bool) {
        return map._indexes[key] != 0;
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function length(IERC20ToBytes32Map storage map) internal view returns (uint256) {
        return map._length;
    }

    /**
     * @dev Returns the key-value pair stored at position `index` in the map. O(1).
     *
     * Note that there are no guarantees on the ordering of entries inside the
     * array, and it may change when more entries are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(IERC20ToBytes32Map storage map, uint256 index) internal view returns (IERC20, bytes32) {
        _require(map._length > index, Errors.OUT_OF_BOUNDS);
        return unchecked_at(map, index);
    }

    /**
     * @dev Same as {at}, except this doesn't revert if `index` it outside of the map (i.e. if it is equal or larger
     * than {length}). O(1).
     *
     * This function performs one less storage read than {at}, but should only be used when `index` is known to be
     * within bounds.
     */
    function unchecked_at(IERC20ToBytes32Map storage map, uint256 index) internal view returns (IERC20, bytes32) {
        IERC20ToBytes32MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    /**
     * @dev Same as {unchecked_At}, except it only returns the value and not the key (performing one less storage
     * read). O(1).
     */
    function unchecked_valueAt(IERC20ToBytes32Map storage map, uint256 index) internal view returns (bytes32) {
        return map._entries[index]._value;
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map. Reverts with `errorCode` otherwise.
     */
    function get(
        IERC20ToBytes32Map storage map,
        IERC20 key,
        uint256 errorCode
    ) internal view returns (bytes32) {
        uint256 index = map._indexes[key];
        _require(index > 0, errorCode);
        return unchecked_valueAt(map, index - 1);
    }

    /**
     * @dev Returns the index for `key` **plus one**. Does not revert if the key is not in the map, and returns 0
     * instead.
     */
    function unchecked_indexOf(IERC20ToBytes32Map storage map, IERC20 key) internal view returns (uint256) {
        return map._indexes[key];
    }
}

File 28 of 45 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../helpers/BalancerErrors.sol";

// Based on the EnumerableSet library from OpenZeppelin contracts, altered to remove the base private functions that
// work on bytes32, replacing them with a native implementation for address values, to reduce bytecode size and runtime
// costs.
// The `unchecked_at` function was also added, which allows for more gas efficient data reads in some scenarios.

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // The original OpenZeppelin implementation uses a generic Set type with bytes32 values: this was replaced with
    // AddressSet, which uses address keys natively, resulting in more dense bytecode.

    struct AddressSet {
        // Storage of set values
        address[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(address => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        if (!contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            address lastValue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastValue;
            // Update the index for the moved value
            set._indexes[lastValue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        _require(set._values.length > index, Errors.OUT_OF_BOUNDS);
        return unchecked_at(set, index);
    }

    /**
     * @dev Same as {at}, except this doesn't revert if `index` it outside of the set (i.e. if it is equal or larger
     * than {length}). O(1).
     *
     * This function performs one less storage read than {at}, but should only be used when `index` is known to be
     * within bounds.
     */
    function unchecked_at(AddressSet storage set, uint256 index) internal view returns (address) {
        return set._values[index];
    }
}

File 29 of 45 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../helpers/BalancerErrors.sol";

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such 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.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        _require(value < 2**255, Errors.SAFE_CAST_VALUE_CANT_FIT_INT256);
        return int256(value);
    }
}

File 30 of 45 : PoolBalances.sol
// 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/Math.sol";
import "../lib/helpers/BalancerErrors.sol";
import "../lib/helpers/InputHelpers.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";
import "../lib/openzeppelin/SafeERC20.sol";

import "./Fees.sol";
import "./PoolTokens.sol";
import "./UserBalance.sol";
import "./interfaces/IBasePool.sol";

/**
 * @dev Stores the Asset Managers (by Pool and token), and implements the top level Asset Manager and Pool interfaces,
 * such as registering and deregistering tokens, joining and exiting Pools, and informational functions like `getPool`
 * and `getPoolTokens`, delegating to specialization-specific functions as needed.
 *
 * `managePoolBalance` handles all Asset Manager interactions.
 */
abstract contract PoolBalances is Fees, ReentrancyGuard, PoolTokens, UserBalance {
    using Math for uint256;
    using SafeERC20 for IERC20;
    using BalanceAllocation for bytes32;
    using BalanceAllocation for bytes32[];

    function joinPool(
        bytes32 poolId,
        address sender,
        address recipient,
        JoinPoolRequest memory request
    ) external payable override whenNotPaused {
        // This function doesn't have the nonReentrant modifier: it is applied to `_joinOrExit` instead.

        // Note that `recipient` is not actually payable in the context of a join - we cast it because we handle both
        // joins and exits at once.
        _joinOrExit(PoolBalanceChangeKind.JOIN, poolId, sender, payable(recipient), _toPoolBalanceChange(request));
    }

    function exitPool(
        bytes32 poolId,
        address sender,
        address payable recipient,
        ExitPoolRequest memory request
    ) external override {
        // This function doesn't have the nonReentrant modifier: it is applied to `_joinOrExit` instead.
        _joinOrExit(PoolBalanceChangeKind.EXIT, poolId, sender, recipient, _toPoolBalanceChange(request));
    }

    // This has the exact same layout as JoinPoolRequest and ExitPoolRequest, except the `maxAmountsIn` and
    // `minAmountsOut` are called `limits`. Internally we use this struct for both since these two functions are quite
    // similar, but expose the others to callers for clarity.
    struct PoolBalanceChange {
        IAsset[] assets;
        uint256[] limits;
        bytes userData;
        bool useInternalBalance;
    }

    /**
     * @dev Converts a JoinPoolRequest into a PoolBalanceChange, with no runtime cost.
     */
    function _toPoolBalanceChange(JoinPoolRequest memory request)
        private
        pure
        returns (PoolBalanceChange memory change)
    {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            change := request
        }
    }

    /**
     * @dev Converts an ExitPoolRequest into a PoolBalanceChange, with no runtime cost.
     */
    function _toPoolBalanceChange(ExitPoolRequest memory request)
        private
        pure
        returns (PoolBalanceChange memory change)
    {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            change := request
        }
    }

    /**
     * @dev Implements both `joinPool` and `exitPool`, based on `kind`.
     */
    function _joinOrExit(
        PoolBalanceChangeKind kind,
        bytes32 poolId,
        address sender,
        address payable recipient,
        PoolBalanceChange memory change
    ) private nonReentrant withRegisteredPool(poolId) authenticateFor(sender) {
        // This function uses a large number of stack variables (poolId, sender and recipient, balances, amounts, fees,
        // etc.), which leads to 'stack too deep' issues. It relies on private functions with seemingly arbitrary
        // interfaces to work around this limitation.

        InputHelpers.ensureInputLengthMatch(change.assets.length, change.limits.length);

        // We first check that the caller passed the Pool's registered tokens in the correct order, and retrieve the
        // current balance for each.
        IERC20[] memory tokens = _translateToIERC20(change.assets);
        bytes32[] memory balances = _validateTokensAndGetBalances(poolId, tokens);

        // The bulk of the work is done here: the corresponding Pool hook is called, its final balances are computed,
        // assets are transferred, and fees are paid.
        (
            bytes32[] memory finalBalances,
            uint256[] memory amountsInOrOut,
            uint256[] memory paidProtocolSwapFeeAmounts
        ) = _callPoolBalanceChange(kind, poolId, sender, recipient, change, balances);

        // All that remains is storing the new Pool balances.
        PoolSpecialization specialization = _getPoolSpecialization(poolId);
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            _setTwoTokenPoolCashBalances(poolId, tokens[0], finalBalances[0], tokens[1], finalBalances[1]);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            _setMinimalSwapInfoPoolBalances(poolId, tokens, finalBalances);
        } else {
            // PoolSpecialization.GENERAL
            _setGeneralPoolBalances(poolId, finalBalances);
        }

        bool positive = kind == PoolBalanceChangeKind.JOIN; // Amounts in are positive, out are negative
        emit PoolBalanceChanged(
            poolId,
            sender,
            tokens,
            // We can unsafely cast to int256 because balances are actually stored as uint112
            _unsafeCastToInt256(amountsInOrOut, positive),
            paidProtocolSwapFeeAmounts
        );
    }

    /**
     * @dev Calls the corresponding Pool hook to get the amounts in/out plus protocol fee amounts, and performs the
     * associated token transfers and fee payments, returning the Pool's final balances.
     */
    function _callPoolBalanceChange(
        PoolBalanceChangeKind kind,
        bytes32 poolId,
        address sender,
        address payable recipient,
        PoolBalanceChange memory change,
        bytes32[] memory balances
    )
        private
        returns (
            bytes32[] memory finalBalances,
            uint256[] memory amountsInOrOut,
            uint256[] memory dueProtocolFeeAmounts
        )
    {
        (uint256[] memory totalBalances, uint256 lastChangeBlock) = balances.totalsAndLastChangeBlock();

        IBasePool pool = IBasePool(_getPoolAddress(poolId));
        (amountsInOrOut, dueProtocolFeeAmounts) = kind == PoolBalanceChangeKind.JOIN
            ? pool.onJoinPool(
                poolId,
                sender,
                recipient,
                totalBalances,
                lastChangeBlock,
                _getProtocolSwapFeePercentage(),
                change.userData
            )
            : pool.onExitPool(
                poolId,
                sender,
                recipient,
                totalBalances,
                lastChangeBlock,
                _getProtocolSwapFeePercentage(),
                change.userData
            );

        InputHelpers.ensureInputLengthMatch(balances.length, amountsInOrOut.length, dueProtocolFeeAmounts.length);

        // The Vault ignores the `recipient` in joins and the `sender` in exits: it is up to the Pool to keep track of
        // their participation.
        finalBalances = kind == PoolBalanceChangeKind.JOIN
            ? _processJoinPoolTransfers(sender, change, balances, amountsInOrOut, dueProtocolFeeAmounts)
            : _processExitPoolTransfers(recipient, change, balances, amountsInOrOut, dueProtocolFeeAmounts);
    }

    /**
     * @dev Transfers `amountsIn` from `sender`, checking that they are within their accepted limits, and pays
     * accumulated protocol swap fees.
     *
     * Returns the Pool's final balances, which are the current balances plus `amountsIn` minus accumulated protocol
     * swap fees.
     */
    function _processJoinPoolTransfers(
        address sender,
        PoolBalanceChange memory change,
        bytes32[] memory balances,
        uint256[] memory amountsIn,
        uint256[] memory dueProtocolFeeAmounts
    ) private returns (bytes32[] memory finalBalances) {
        // We need to track how much of the received ETH was used and wrapped into WETH to return any excess.
        uint256 wrappedEth = 0;

        finalBalances = new bytes32[](balances.length);
        for (uint256 i = 0; i < change.assets.length; ++i) {
            uint256 amountIn = amountsIn[i];
            _require(amountIn <= change.limits[i], Errors.JOIN_ABOVE_MAX);

            // Receive assets from the sender - possibly from Internal Balance.
            IAsset asset = change.assets[i];
            _receiveAsset(asset, amountIn, sender, change.useInternalBalance);

            if (_isETH(asset)) {
                wrappedEth = wrappedEth.add(amountIn);
            }

            uint256 feeAmount = dueProtocolFeeAmounts[i];
            _payFeeAmount(_translateToIERC20(asset), feeAmount);

            // Compute the new Pool balances. Note that the fee amount might be larger than `amountIn`,
            // resulting in an overall decrease of the Pool's balance for a token.
            finalBalances[i] = (amountIn >= feeAmount) // This lets us skip checked arithmetic
                ? balances[i].increaseCash(amountIn - feeAmount)
                : balances[i].decreaseCash(feeAmount - amountIn);
        }

        // Handle any used and remaining ETH.
        _handleRemainingEth(wrappedEth);
    }

    /**
     * @dev Transfers `amountsOut` to `recipient`, checking that they are within their accepted limits, and pays
     * accumulated protocol swap fees from the Pool.
     *
     * Returns the Pool's final balances, which are the current `balances` minus `amountsOut` and fees paid
     * (`dueProtocolFeeAmounts`).
     */
    function _processExitPoolTransfers(
        address payable recipient,
        PoolBalanceChange memory change,
        bytes32[] memory balances,
        uint256[] memory amountsOut,
        uint256[] memory dueProtocolFeeAmounts
    ) private returns (bytes32[] memory finalBalances) {
        finalBalances = new bytes32[](balances.length);
        for (uint256 i = 0; i < change.assets.length; ++i) {
            uint256 amountOut = amountsOut[i];
            _require(amountOut >= change.limits[i], Errors.EXIT_BELOW_MIN);

            // Send tokens to the recipient - possibly to Internal Balance
            IAsset asset = change.assets[i];
            _sendAsset(asset, amountOut, recipient, change.useInternalBalance);

            uint256 feeAmount = dueProtocolFeeAmounts[i];
            _payFeeAmount(_translateToIERC20(asset), feeAmount);

            // Compute the new Pool balances. A Pool's token balance always decreases after an exit (potentially by 0).
            finalBalances[i] = balances[i].decreaseCash(amountOut.add(feeAmount));
        }
    }

    /**
     * @dev Returns the total balance for `poolId`'s `expectedTokens`.
     *
     * `expectedTokens` must exactly equal the token array returned by `getPoolTokens`: both arrays must have the same
     * length, elements and order. Additionally, the Pool must have at least one registered token.
     */
    function _validateTokensAndGetBalances(bytes32 poolId, IERC20[] memory expectedTokens)
        private
        view
        returns (bytes32[] memory)
    {
        (IERC20[] memory actualTokens, bytes32[] memory balances) = _getPoolTokens(poolId);
        InputHelpers.ensureInputLengthMatch(actualTokens.length, expectedTokens.length);
        _require(actualTokens.length > 0, Errors.POOL_NO_TOKENS);

        for (uint256 i = 0; i < actualTokens.length; ++i) {
            _require(actualTokens[i] == expectedTokens[i], Errors.TOKENS_MISMATCH);
        }

        return balances;
    }

    /**
     * @dev Casts an array of uint256 to int256, setting the sign of the result according to the `positive` flag,
     * without checking whether the values fit in the signed 256 bit range.
     */
    function _unsafeCastToInt256(uint256[] memory values, bool positive)
        private
        pure
        returns (int256[] memory signedValues)
    {
        signedValues = new int256[](values.length);
        for (uint256 i = 0; i < values.length; i++) {
            signedValues[i] = positive ? int256(values[i]) : -int256(values[i]);
        }
    }
}

File 31 of 45 : IPoolSwapStructs.sol
// 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;
    }
}

File 32 of 45 : IGeneralPool.sol
// 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 IPools with the General specialization setting 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 IGeneralPool is IBasePool {
    function onSwap(
        SwapRequest memory swapRequest,
        uint256[] memory balances,
        uint256 indexIn,
        uint256 indexOut
    ) external returns (uint256 amount);
}

File 33 of 45 : IMinimalSwapInfoPool.sol
// 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);
}

File 34 of 45 : BalanceAllocation.sol
// 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";

// This library is used to create a data structure that represents a token's balance for a Pool. 'cash' is how many
// tokens the Pool has sitting inside of the Vault. 'managed' is how many tokens were withdrawn from the Vault by the
// Pool's Asset Manager. 'total' is the sum of these two, and represents the Pool's total token balance, including
// tokens that are *not* inside of the Vault.
//
// 'cash' is updated whenever tokens enter and exit the Vault, while 'managed' is only updated if the reason tokens are
// moving is due to an Asset Manager action. This is reflected in the different methods available: 'increaseCash'
// and 'decreaseCash' for swaps and add/remove liquidity events, and 'cashToManaged' and 'managedToCash' for events
// transferring funds to and from the Asset Manager.
//
// The Vault disallows the Pool's 'cash' from becoming negative. In other words, it can never use any tokens that are
// not inside the Vault.
//
// One of the goals of this library is to store the entire token balance in a single storage slot, which is why we use
// 112 bit unsigned integers for 'cash' and 'managed'. For consistency, we also disallow any combination of 'cash' and
// 'managed' that yields a 'total' that doesn't fit in 112 bits.
//
// The remaining 32 bits of the slot are used to store the most recent block when the total balance changed. This
// can be used to implement price oracles that are resilient to 'sandwich' attacks.
//
// We could use a Solidity struct to pack these three values together in a single storage slot, but unfortunately
// Solidity only allows for structs to live in either storage, calldata or memory. Because a memory struct still takes
// up a slot in the stack (to store its memory location), and because the entire balance fits in a single stack slot
// (two 112 bit values plus the 32 bit block), using memory is strictly less gas performant. Therefore, we do manual
// packing and unpacking.
//
// Since we cannot define new types, we rely on bytes32 to represent these values instead, as it doesn't have any
// associated arithmetic operations and therefore reduces the chance of misuse.
library BalanceAllocation {
    using Math for uint256;

    // The 'cash' portion of the balance is stored in the least significant 112 bits of a 256 bit word, while the
    // 'managed' part uses the following 112 bits. The most significant 32 bits are used to store the block

    /**
     * @dev Returns the total amount of Pool tokens, including those that are not currently in the Vault ('managed').
     */
    function total(bytes32 balance) internal pure returns (uint256) {
        // Since 'cash' and 'managed' are 112 bit values, we don't need checked arithmetic. Additionally, `toBalance`
        // ensures that 'total' always fits in 112 bits.
        return cash(balance) + managed(balance);
    }

    /**
     * @dev Returns the amount of Pool tokens currently in the Vault.
     */
    function cash(bytes32 balance) internal pure returns (uint256) {
        uint256 mask = 2**(112) - 1;
        return uint256(balance) & mask;
    }

    /**
     * @dev Returns the amount of Pool tokens that are being managed by an Asset Manager.
     */
    function managed(bytes32 balance) internal pure returns (uint256) {
        uint256 mask = 2**(112) - 1;
        return uint256(balance >> 112) & mask;
    }

    /**
     * @dev Returns the last block when the total balance changed.
     */
    function lastChangeBlock(bytes32 balance) internal pure returns (uint256) {
        uint256 mask = 2**(32) - 1;
        return uint256(balance >> 224) & mask;
    }

    /**
     * @dev Returns the difference in 'managed' between two balances.
     */
    function managedDelta(bytes32 newBalance, bytes32 oldBalance) internal pure returns (int256) {
        // Because `managed` is a 112 bit value, we can safely perform unchecked arithmetic in 256 bits.
        return int256(managed(newBalance)) - int256(managed(oldBalance));
    }

    /**
     * @dev Returns the total balance for each entry in `balances`, as well as the latest block when the total
     * balance of *any* of them last changed.
     */
    function totalsAndLastChangeBlock(bytes32[] memory balances)
        internal
        pure
        returns (
            uint256[] memory results,
            uint256 lastChangeBlock_ // Avoid shadowing
        )
    {
        results = new uint256[](balances.length);
        lastChangeBlock_ = 0;

        for (uint256 i = 0; i < results.length; i++) {
            bytes32 balance = balances[i];
            results[i] = total(balance);
            lastChangeBlock_ = Math.max(lastChangeBlock_, lastChangeBlock(balance));
        }
    }

    /**
     * @dev Returns true if `balance`'s 'total' balance is zero. Costs less gas than computing 'total' and comparing
     * with zero.
     */
    function isZero(bytes32 balance) internal pure returns (bool) {
        // We simply need to check the least significant 224 bytes of the word: the block does not affect this.
        uint256 mask = 2**(224) - 1;
        return (uint256(balance) & mask) == 0;
    }

    /**
     * @dev Returns true if `balance`'s 'total' balance is not zero. Costs less gas than computing 'total' and comparing
     * with zero.
     */
    function isNotZero(bytes32 balance) internal pure returns (bool) {
        return !isZero(balance);
    }

    /**
     * @dev Packs together `cash` and `managed` amounts with a block to create a balance value.
     *
     * For consistency, this also checks that the sum of `cash` and `managed` (`total`) fits in 112 bits.
     */
    function toBalance(
        uint256 _cash,
        uint256 _managed,
        uint256 _blockNumber
    ) internal pure returns (bytes32) {
        uint256 _total = _cash + _managed;

        // Since both 'cash' and 'managed' are positive integers, by checking that their sum ('total') fits in 112 bits
        // we are also indirectly checking that both 'cash' and 'managed' themselves fit in 112 bits.
        _require(_total >= _cash && _total < 2**112, Errors.BALANCE_TOTAL_OVERFLOW);

        // We assume the block fits in 32 bits - this is expected to hold for at least a few decades.
        return _pack(_cash, _managed, _blockNumber);
    }

    /**
     * @dev Increases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent to the Vault (except
     * for Asset Manager deposits).
     *
     * Updates the last total balance change block, even if `amount` is zero.
     */
    function increaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) {
        uint256 newCash = cash(balance).add(amount);
        uint256 currentManaged = managed(balance);
        uint256 newLastChangeBlock = block.number;

        return toBalance(newCash, currentManaged, newLastChangeBlock);
    }

    /**
     * @dev Decreases a Pool's 'cash' (and therefore its 'total'). Called when Pool tokens are sent from the Vault
     * (except for Asset Manager withdrawals).
     *
     * Updates the last total balance change block, even if `amount` is zero.
     */
    function decreaseCash(bytes32 balance, uint256 amount) internal view returns (bytes32) {
        uint256 newCash = cash(balance).sub(amount);
        uint256 currentManaged = managed(balance);
        uint256 newLastChangeBlock = block.number;

        return toBalance(newCash, currentManaged, newLastChangeBlock);
    }

    /**
     * @dev Moves 'cash' into 'managed', leaving 'total' unchanged. Called when an Asset Manager withdraws Pool tokens
     * from the Vault.
     */
    function cashToManaged(bytes32 balance, uint256 amount) internal pure returns (bytes32) {
        uint256 newCash = cash(balance).sub(amount);
        uint256 newManaged = managed(balance).add(amount);
        uint256 currentLastChangeBlock = lastChangeBlock(balance);

        return toBalance(newCash, newManaged, currentLastChangeBlock);
    }

    /**
     * @dev Moves 'managed' into 'cash', leaving 'total' unchanged. Called when an Asset Manager deposits Pool tokens
     * into the Vault.
     */
    function managedToCash(bytes32 balance, uint256 amount) internal pure returns (bytes32) {
        uint256 newCash = cash(balance).add(amount);
        uint256 newManaged = managed(balance).sub(amount);
        uint256 currentLastChangeBlock = lastChangeBlock(balance);

        return toBalance(newCash, newManaged, currentLastChangeBlock);
    }

    /**
     * @dev Sets 'managed' balance to an arbitrary value, changing 'total'. Called when the Asset Manager reports
     * profits or losses. It's the Manager's responsibility to provide a meaningful value.
     *
     * Updates the last total balance change block, even if `newManaged` is equal to the current 'managed' value.
     */
    function setManaged(bytes32 balance, uint256 newManaged) internal view returns (bytes32) {
        uint256 currentCash = cash(balance);
        uint256 newLastChangeBlock = block.number;
        return toBalance(currentCash, newManaged, newLastChangeBlock);
    }

    // Alternative mode for Pools with the Two Token specialization setting

    // Instead of storing cash and external for each 'token in' a single storage slot, Two Token Pools store the cash
    // for both tokens in the same slot, and the managed for both in another one. This reduces the gas cost for swaps,
    // because the only slot that needs to be updated is the one with the cash. However, it also means that managing
    // balances is more cumbersome, as both tokens need to be read/written at the same time.
    //
    // The field with both cash balances packed is called sharedCash, and the one with external amounts is called
    // sharedManaged. These two are collectively called the 'shared' balance fields. In both of these, the portion
    // that corresponds to token A is stored in the least significant 112 bits of a 256 bit word, while token B's part
    // uses the next least significant 112 bits.
    //
    // Because only cash is written to during a swap, we store the last total balance change block with the
    // packed cash fields. Typically Pools have a distinct block per token: in the case of Two Token Pools they
    // are the same.

    /**
     * @dev Extracts the part of the balance that corresponds to token A. This function can be used to decode both
     * shared cash and managed balances.
     */
    function _decodeBalanceA(bytes32 sharedBalance) private pure returns (uint256) {
        uint256 mask = 2**(112) - 1;
        return uint256(sharedBalance) & mask;
    }

    /**
     * @dev Extracts the part of the balance that corresponds to token B. This function can be used to decode both
     * shared cash and managed balances.
     */
    function _decodeBalanceB(bytes32 sharedBalance) private pure returns (uint256) {
        uint256 mask = 2**(112) - 1;
        return uint256(sharedBalance >> 112) & mask;
    }

    // To decode the last balance change block, we can simply use the `blockNumber` function.

    /**
     * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token A.
     */
    function fromSharedToBalanceA(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) {
        // Note that we extract the block from the sharedCash field, which is the one that is updated by swaps.
        // Both token A and token B use the same block
        return toBalance(_decodeBalanceA(sharedCash), _decodeBalanceA(sharedManaged), lastChangeBlock(sharedCash));
    }

    /**
     * @dev Unpacks the shared token A and token B cash and managed balances into the balance for token B.
     */
    function fromSharedToBalanceB(bytes32 sharedCash, bytes32 sharedManaged) internal pure returns (bytes32) {
        // Note that we extract the block from the sharedCash field, which is the one that is updated by swaps.
        // Both token A and token B use the same block
        return toBalance(_decodeBalanceB(sharedCash), _decodeBalanceB(sharedManaged), lastChangeBlock(sharedCash));
    }

    /**
     * @dev Returns the sharedCash shared field, given the current balances for token A and token B.
     */
    function toSharedCash(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) {
        // Both balances are assigned the same block  Since it is possible a single one of them has changed (for
        // example, in an Asset Manager update), we keep the latest (largest) one.
        uint32 newLastChangeBlock = uint32(Math.max(lastChangeBlock(tokenABalance), lastChangeBlock(tokenBBalance)));

        return _pack(cash(tokenABalance), cash(tokenBBalance), newLastChangeBlock);
    }

    /**
     * @dev Returns the sharedManaged shared field, given the current balances for token A and token B.
     */
    function toSharedManaged(bytes32 tokenABalance, bytes32 tokenBBalance) internal pure returns (bytes32) {
        // We don't bother storing a last change block, as it is read from the shared cash field.
        return _pack(managed(tokenABalance), managed(tokenBBalance), 0);
    }

    // Shared functions

    /**
     * @dev Packs together two uint112 and one uint32 into a bytes32
     */
    function _pack(
        uint256 _leastSignificant,
        uint256 _midSignificant,
        uint256 _mostSignificant
    ) private pure returns (bytes32) {
        return bytes32((_mostSignificant << 224) + (_midSignificant << 112) + _leastSignificant);
    }
}

File 35 of 45 : PoolTokens.sol
// 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/helpers/BalancerErrors.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";

import "./AssetManagers.sol";
import "./PoolRegistry.sol";
import "./balances/BalanceAllocation.sol";

abstract contract PoolTokens is ReentrancyGuard, PoolRegistry, AssetManagers {
    using BalanceAllocation for bytes32;
    using BalanceAllocation for bytes32[];

    function registerTokens(
        bytes32 poolId,
        IERC20[] memory tokens,
        address[] memory assetManagers
    ) external override nonReentrant whenNotPaused onlyPool(poolId) {
        InputHelpers.ensureInputLengthMatch(tokens.length, assetManagers.length);

        // Validates token addresses and assigns Asset Managers
        for (uint256 i = 0; i < tokens.length; ++i) {
            IERC20 token = tokens[i];
            _require(token != IERC20(0), Errors.INVALID_TOKEN);

            _poolAssetManagers[poolId][token] = assetManagers[i];
        }

        PoolSpecialization specialization = _getPoolSpecialization(poolId);
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            _require(tokens.length == 2, Errors.TOKENS_LENGTH_MUST_BE_2);
            _registerTwoTokenPoolTokens(poolId, tokens[0], tokens[1]);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            _registerMinimalSwapInfoPoolTokens(poolId, tokens);
        } else {
            // PoolSpecialization.GENERAL
            _registerGeneralPoolTokens(poolId, tokens);
        }

        emit TokensRegistered(poolId, tokens, assetManagers);
    }

    function deregisterTokens(bytes32 poolId, IERC20[] memory tokens)
        external
        override
        nonReentrant
        whenNotPaused
        onlyPool(poolId)
    {
        PoolSpecialization specialization = _getPoolSpecialization(poolId);
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            _require(tokens.length == 2, Errors.TOKENS_LENGTH_MUST_BE_2);
            _deregisterTwoTokenPoolTokens(poolId, tokens[0], tokens[1]);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            _deregisterMinimalSwapInfoPoolTokens(poolId, tokens);
        } else {
            // PoolSpecialization.GENERAL
            _deregisterGeneralPoolTokens(poolId, tokens);
        }

        // The deregister calls above ensure the total token balance is zero. Therefore it is now safe to remove any
        // associated Asset Managers, since they hold no Pool balance.
        for (uint256 i = 0; i < tokens.length; ++i) {
            delete _poolAssetManagers[poolId][tokens[i]];
        }

        emit TokensDeregistered(poolId, tokens);
    }

    function getPoolTokens(bytes32 poolId)
        external
        view
        override
        withRegisteredPool(poolId)
        returns (
            IERC20[] memory tokens,
            uint256[] memory balances,
            uint256 lastChangeBlock
        )
    {
        bytes32[] memory rawBalances;
        (tokens, rawBalances) = _getPoolTokens(poolId);
        (balances, lastChangeBlock) = rawBalances.totalsAndLastChangeBlock();
    }

    function getPoolTokenInfo(bytes32 poolId, IERC20 token)
        external
        view
        override
        withRegisteredPool(poolId)
        returns (
            uint256 cash,
            uint256 managed,
            uint256 lastChangeBlock,
            address assetManager
        )
    {
        bytes32 balance;
        PoolSpecialization specialization = _getPoolSpecialization(poolId);

        if (specialization == PoolSpecialization.TWO_TOKEN) {
            balance = _getTwoTokenPoolBalance(poolId, token);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            balance = _getMinimalSwapInfoPoolBalance(poolId, token);
        } else {
            // PoolSpecialization.GENERAL
            balance = _getGeneralPoolBalance(poolId, token);
        }

        cash = balance.cash();
        managed = balance.managed();
        lastChangeBlock = balance.lastChangeBlock();
        assetManager = _poolAssetManagers[poolId][token];
    }

    /**
     * @dev Returns all of `poolId`'s registered tokens, along with their raw balances.
     */
    function _getPoolTokens(bytes32 poolId) internal view returns (IERC20[] memory tokens, bytes32[] memory balances) {
        PoolSpecialization specialization = _getPoolSpecialization(poolId);
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            return _getTwoTokenPoolTokens(poolId);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            return _getMinimalSwapInfoPoolTokens(poolId);
        } else {
            // PoolSpecialization.GENERAL
            return _getGeneralPoolTokens(poolId);
        }
    }
}

File 36 of 45 : UserBalance.sol
// 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/helpers/BalancerErrors.sol";
import "../lib/math/Math.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";
import "../lib/openzeppelin/SafeCast.sol";
import "../lib/openzeppelin/SafeERC20.sol";

import "./AssetTransfersHandler.sol";
import "./VaultAuthorization.sol";

/**
 * Implement User Balance interactions, which combine Internal Balance and using the Vault's ERC20 allowance.
 *
 * 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.
 */
abstract contract UserBalance is ReentrancyGuard, AssetTransfersHandler, VaultAuthorization {
    using Math for uint256;
    using SafeCast for uint256;
    using SafeERC20 for IERC20;

    // Internal Balance for each token, for each account.
    mapping(address => mapping(IERC20 => uint256)) private _internalTokenBalance;

    function getInternalBalance(address user, IERC20[] memory tokens)
        external
        view
        override
        returns (uint256[] memory balances)
    {
        balances = new uint256[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            balances[i] = _getInternalBalance(user, tokens[i]);
        }
    }

    function manageUserBalance(UserBalanceOp[] memory ops) external payable override nonReentrant {
        // We need to track how much of the received ETH was used and wrapped into WETH to return any excess.
        uint256 ethWrapped = 0;

        // Cache for these checks so we only perform them once (if at all).
        bool checkedCallerIsRelayer = false;
        bool checkedNotPaused = false;

        for (uint256 i = 0; i < ops.length; i++) {
            UserBalanceOpKind kind;
            IAsset asset;
            uint256 amount;
            address sender;
            address payable recipient;

            // This destructuring by calling `_validateUserBalanceOp` seems odd, but results in reduced bytecode size.
            (kind, asset, amount, sender, recipient, checkedCallerIsRelayer) = _validateUserBalanceOp(
                ops[i],
                checkedCallerIsRelayer
            );

            if (kind == UserBalanceOpKind.WITHDRAW_INTERNAL) {
                // Internal Balance withdrawals can always be performed by an authorized account.
                _withdrawFromInternalBalance(asset, sender, recipient, amount);
            } else {
                // All other operations are blocked if the contract is paused.

                // We cache the result of the pause check and skip it for other operations in this same transaction
                // (if any).
                if (!checkedNotPaused) {
                    _ensureNotPaused();
                    checkedNotPaused = true;
                }

                if (kind == UserBalanceOpKind.DEPOSIT_INTERNAL) {
                    _depositToInternalBalance(asset, sender, recipient, amount);

                    // Keep track of all ETH wrapped into WETH as part of a deposit.
                    if (_isETH(asset)) {
                        ethWrapped = ethWrapped.add(amount);
                    }
                } else {
                    // Transfers don't support ETH.
                    _require(!_isETH(asset), Errors.CANNOT_USE_ETH_SENTINEL);
                    IERC20 token = _asIERC20(asset);

                    if (kind == UserBalanceOpKind.TRANSFER_INTERNAL) {
                        _transferInternalBalance(token, sender, recipient, amount);
                    } else {
                        // TRANSFER_EXTERNAL
                        _transferToExternalBalance(token, sender, recipient, amount);
                    }
                }
            }
        }

        // Handle any remaining ETH.
        _handleRemainingEth(ethWrapped);
    }

    function _depositToInternalBalance(
        IAsset asset,
        address sender,
        address recipient,
        uint256 amount
    ) private {
        _increaseInternalBalance(recipient, _translateToIERC20(asset), amount);
        _receiveAsset(asset, amount, sender, false);
    }

    function _withdrawFromInternalBalance(
        IAsset asset,
        address sender,
        address payable recipient,
        uint256 amount
    ) private {
        // A partial decrease of Internal Balance is disallowed: `sender` must have the full `amount`.
        _decreaseInternalBalance(sender, _translateToIERC20(asset), amount, false);
        _sendAsset(asset, amount, recipient, false);
    }

    function _transferInternalBalance(
        IERC20 token,
        address sender,
        address recipient,
        uint256 amount
    ) private {
        // A partial decrease of Internal Balance is disallowed: `sender` must have the full `amount`.
        _decreaseInternalBalance(sender, token, amount, false);
        _increaseInternalBalance(recipient, token, amount);
    }

    function _transferToExternalBalance(
        IERC20 token,
        address sender,
        address recipient,
        uint256 amount
    ) private {
        if (amount > 0) {
            token.safeTransferFrom(sender, recipient, amount);
            emit ExternalBalanceTransfer(token, sender, recipient, amount);
        }
    }

    /**
     * @dev Increases `account`'s Internal Balance for `token` by `amount`.
     */
    function _increaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount
    ) internal override {
        uint256 currentBalance = _getInternalBalance(account, token);
        uint256 newBalance = currentBalance.add(amount);
        _setInternalBalance(account, token, newBalance, amount.toInt256());
    }

    /**
     * @dev Decreases `account`'s Internal Balance for `token` by `amount`. If `allowPartial` is true, this function
     * doesn't revert if `account` doesn't have enough balance, and sets it to zero and returns the deducted amount
     * instead.
     */
    function _decreaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount,
        bool allowPartial
    ) internal override returns (uint256 deducted) {
        uint256 currentBalance = _getInternalBalance(account, token);
        _require(allowPartial || (currentBalance >= amount), Errors.INSUFFICIENT_INTERNAL_BALANCE);

        deducted = Math.min(currentBalance, amount);
        // By construction, `deducted` is lower or equal to `currentBalance`, so we don't need to use checked
        // arithmetic.
        uint256 newBalance = currentBalance - deducted;
        _setInternalBalance(account, token, newBalance, -(deducted.toInt256()));
    }

    /**
     * @dev Sets `account`'s Internal Balance for `token` to `newBalance`.
     *
     * Emits an `InternalBalanceChanged` event. This event includes `delta`, which is the amount the balance increased
     * (if positive) or decreased (if negative). To avoid reading the current balance in order to compute the delta,
     * this function relies on the caller providing it directly.
     */
    function _setInternalBalance(
        address account,
        IERC20 token,
        uint256 newBalance,
        int256 delta
    ) private {
        _internalTokenBalance[account][token] = newBalance;
        emit InternalBalanceChanged(account, token, delta);
    }

    /**
     * @dev Returns `account`'s Internal Balance for `token`.
     */
    function _getInternalBalance(address account, IERC20 token) internal view returns (uint256) {
        return _internalTokenBalance[account][token];
    }

    /**
     * @dev Destructures a User Balance operation, validating that the contract caller is allowed to perform it.
     */
    function _validateUserBalanceOp(UserBalanceOp memory op, bool checkedCallerIsRelayer)
        private
        view
        returns (
            UserBalanceOpKind,
            IAsset,
            uint256,
            address,
            address payable,
            bool
        )
    {
        // The only argument we need to validate is `sender`, which can only be either the contract caller, or a
        // relayer approved by `sender`.
        address sender = op.sender;

        if (sender != msg.sender) {
            // We need to check both that the contract caller is a relayer, and that `sender` approved them.

            // Because the relayer check is global (i.e. independent of `sender`), we cache that result and skip it for
            // other operations in this same transaction (if any).
            if (!checkedCallerIsRelayer) {
                _authenticateCaller();
                checkedCallerIsRelayer = true;
            }

            _require(_hasApprovedRelayer(sender, msg.sender), Errors.USER_DOESNT_ALLOW_RELAYER);
        }

        return (op.kind, op.asset, op.amount, sender, op.recipient, checkedCallerIsRelayer);
    }
}

File 37 of 45 : IBasePool.sol
// 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);
}

File 38 of 45 : AssetManagers.sol
// 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/Math.sol";
import "../lib/helpers/BalancerErrors.sol";
import "../lib/helpers/InputHelpers.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/openzeppelin/SafeERC20.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";

import "./UserBalance.sol";
import "./balances/BalanceAllocation.sol";
import "./balances/GeneralPoolsBalance.sol";
import "./balances/MinimalSwapInfoPoolsBalance.sol";
import "./balances/TwoTokenPoolsBalance.sol";

abstract contract AssetManagers is
    ReentrancyGuard,
    GeneralPoolsBalance,
    MinimalSwapInfoPoolsBalance,
    TwoTokenPoolsBalance
{
    using Math for uint256;
    using SafeERC20 for IERC20;

    // Stores the Asset Manager for each token of each Pool.
    mapping(bytes32 => mapping(IERC20 => address)) internal _poolAssetManagers;

    function managePoolBalance(PoolBalanceOp[] memory ops) external override nonReentrant whenNotPaused {
        // This variable could be declared inside the loop, but that causes the compiler to allocate memory on each
        // loop iteration, increasing gas costs.
        PoolBalanceOp memory op;

        for (uint256 i = 0; i < ops.length; ++i) {
            // By indexing the array only once, we don't spend extra gas in the same bounds check.
            op = ops[i];

            bytes32 poolId = op.poolId;
            _ensureRegisteredPool(poolId);

            IERC20 token = op.token;
            _require(_isTokenRegistered(poolId, token), Errors.TOKEN_NOT_REGISTERED);
            _require(_poolAssetManagers[poolId][token] == msg.sender, Errors.SENDER_NOT_ASSET_MANAGER);

            PoolBalanceOpKind kind = op.kind;
            uint256 amount = op.amount;
            (int256 cashDelta, int256 managedDelta) = _performPoolManagementOperation(kind, poolId, token, amount);

            emit PoolBalanceManaged(poolId, msg.sender, token, cashDelta, managedDelta);
        }
    }

    /**
     * @dev Performs the `kind` Asset Manager operation on a Pool.
     *
     * Withdrawals will transfer `amount` tokens to the caller, deposits will transfer `amount` tokens from the caller,
     * and updates will set the managed balance to `amount`.
     *
     * Returns a tuple with the 'cash' and 'managed' balance deltas as a result of this call.
     */
    function _performPoolManagementOperation(
        PoolBalanceOpKind kind,
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) private returns (int256, int256) {
        PoolSpecialization specialization = _getPoolSpecialization(poolId);

        if (kind == PoolBalanceOpKind.WITHDRAW) {
            return _withdrawPoolBalance(poolId, specialization, token, amount);
        } else if (kind == PoolBalanceOpKind.DEPOSIT) {
            return _depositPoolBalance(poolId, specialization, token, amount);
        } else {
            // PoolBalanceOpKind.UPDATE
            return _updateManagedBalance(poolId, specialization, token, amount);
        }
    }

    /**
     * @dev Moves `amount` tokens from a Pool's 'cash' to 'managed' balance, and transfers them to the caller.
     *
     * Returns the 'cash' and 'managed' balance deltas as a result of this call, which will be complementary.
     */
    function _withdrawPoolBalance(
        bytes32 poolId,
        PoolSpecialization specialization,
        IERC20 token,
        uint256 amount
    ) private returns (int256 cashDelta, int256 managedDelta) {
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            _twoTokenPoolCashToManaged(poolId, token, amount);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            _minimalSwapInfoPoolCashToManaged(poolId, token, amount);
        } else {
            // PoolSpecialization.GENERAL
            _generalPoolCashToManaged(poolId, token, amount);
        }

        if (amount > 0) {
            token.safeTransfer(msg.sender, amount);
        }

        // Since 'cash' and 'managed' are stored as uint112, `amount` is guaranteed to also fit in 112 bits. It will
        // therefore always fit in a 256 bit integer.
        cashDelta = int256(-amount);
        managedDelta = int256(amount);
    }

    /**
     * @dev Moves `amount` tokens from a Pool's 'managed' to 'cash' balance, and transfers them from the caller.
     *
     * Returns the 'cash' and 'managed' balance deltas as a result of this call, which will be complementary.
     */
    function _depositPoolBalance(
        bytes32 poolId,
        PoolSpecialization specialization,
        IERC20 token,
        uint256 amount
    ) private returns (int256 cashDelta, int256 managedDelta) {
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            _twoTokenPoolManagedToCash(poolId, token, amount);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            _minimalSwapInfoPoolManagedToCash(poolId, token, amount);
        } else {
            // PoolSpecialization.GENERAL
            _generalPoolManagedToCash(poolId, token, amount);
        }

        if (amount > 0) {
            token.safeTransferFrom(msg.sender, address(this), amount);
        }

        // Since 'cash' and 'managed' are stored as uint112, `amount` is guaranteed to also fit in 112 bits. It will
        // therefore always fit in a 256 bit integer.
        cashDelta = int256(amount);
        managedDelta = int256(-amount);
    }

    /**
     * @dev Sets a Pool's 'managed' balance to `amount`.
     *
     * Returns the 'cash' and 'managed' balance deltas as a result of this call (the 'cash' delta will always be zero).
     */
    function _updateManagedBalance(
        bytes32 poolId,
        PoolSpecialization specialization,
        IERC20 token,
        uint256 amount
    ) private returns (int256 cashDelta, int256 managedDelta) {
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            managedDelta = _setTwoTokenPoolManagedBalance(poolId, token, amount);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            managedDelta = _setMinimalSwapInfoPoolManagedBalance(poolId, token, amount);
        } else {
            // PoolSpecialization.GENERAL
            managedDelta = _setGeneralPoolManagedBalance(poolId, token, amount);
        }

        cashDelta = 0;
    }

    /**
     * @dev Returns true if `token` is registered for `poolId`.
     */
    function _isTokenRegistered(bytes32 poolId, IERC20 token) private view returns (bool) {
        PoolSpecialization specialization = _getPoolSpecialization(poolId);
        if (specialization == PoolSpecialization.TWO_TOKEN) {
            return _isTwoTokenPoolTokenRegistered(poolId, token);
        } else if (specialization == PoolSpecialization.MINIMAL_SWAP_INFO) {
            return _isMinimalSwapInfoPoolTokenRegistered(poolId, token);
        } else {
            // PoolSpecialization.GENERAL
            return _isGeneralPoolTokenRegistered(poolId, token);
        }
    }
}

File 39 of 45 : PoolRegistry.sol
// 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/helpers/BalancerErrors.sol";
import "../lib/openzeppelin/ReentrancyGuard.sol";

import "./VaultAuthorization.sol";

/**
 * @dev Maintains the Pool ID data structure, implements Pool ID creation and registration, and defines useful modifiers
 * and helper functions for ensuring correct behavior when working with Pools.
 */
abstract contract PoolRegistry is ReentrancyGuard, VaultAuthorization {
    // Each pool is represented by their unique Pool ID. We use `bytes32` for them, for lack of a way to define new
    // types.
    mapping(bytes32 => bool) private _isPoolRegistered;

    // We keep an increasing nonce to make Pool IDs unique. It is interpreted as a `uint80`, but storing it as a
    // `uint256` results in reduced bytecode on reads and writes due to the lack of masking.
    uint256 private _nextPoolNonce;

    /**
     * @dev Reverts unless `poolId` corresponds to a registered Pool.
     */
    modifier withRegisteredPool(bytes32 poolId) {
        _ensureRegisteredPool(poolId);
        _;
    }

    /**
     * @dev Reverts unless `poolId` corresponds to a registered Pool, and the caller is the Pool's contract.
     */
    modifier onlyPool(bytes32 poolId) {
        _ensurePoolIsSender(poolId);
        _;
    }

    /**
     * @dev Reverts unless `poolId` corresponds to a registered Pool.
     */
    function _ensureRegisteredPool(bytes32 poolId) internal view {
        _require(_isPoolRegistered[poolId], Errors.INVALID_POOL_ID);
    }

    /**
     * @dev Reverts unless `poolId` corresponds to a registered Pool, and the caller is the Pool's contract.
     */
    function _ensurePoolIsSender(bytes32 poolId) private view {
        _ensureRegisteredPool(poolId);
        _require(msg.sender == _getPoolAddress(poolId), Errors.CALLER_NOT_POOL);
    }

    function registerPool(PoolSpecialization specialization)
        external
        override
        nonReentrant
        whenNotPaused
        returns (bytes32)
    {
        // Each Pool is assigned a unique ID based on an incrementing nonce. This assumes there will never be more than
        // 2**80 Pools, and the nonce will not overflow.

        bytes32 poolId = _toPoolId(msg.sender, specialization, uint80(_nextPoolNonce));

        _require(!_isPoolRegistered[poolId], Errors.INVALID_POOL_ID); // Should never happen as Pool IDs are unique.
        _isPoolRegistered[poolId] = true;

        _nextPoolNonce += 1;

        // Note that msg.sender is the pool's contract
        emit PoolRegistered(poolId, msg.sender, specialization);
        return poolId;
    }

    function getPool(bytes32 poolId)
        external
        view
        override
        withRegisteredPool(poolId)
        returns (address, PoolSpecialization)
    {
        return (_getPoolAddress(poolId), _getPoolSpecialization(poolId));
    }

    /**
     * @dev Creates a Pool ID.
     *
     * These are deterministically created by packing the Pool's contract address and its specialization setting into
     * the ID. This saves gas by making this data easily retrievable from a Pool ID with no storage accesses.
     *
     * Since a single contract can register multiple Pools, a unique nonce must be provided to ensure Pool IDs are
     * unique.
     *
     * Pool IDs have the following layout:
     * | 20 bytes pool contract address | 2 bytes specialization setting | 10 bytes nonce |
     * MSB                                                                              LSB
     *
     * 2 bytes for the specialization setting is a bit overkill: there only three of them, which means two bits would
     * suffice. However, there's nothing else of interest to store in this extra space.
     */
    function _toPoolId(
        address pool,
        PoolSpecialization specialization,
        uint80 nonce
    ) internal pure returns (bytes32) {
        bytes32 serialized;

        serialized |= bytes32(uint256(nonce));
        serialized |= bytes32(uint256(specialization)) << (10 * 8);
        serialized |= bytes32(uint256(pool)) << (12 * 8);

        return serialized;
    }

    /**
     * @dev Returns the address of a Pool's contract.
     *
     * Due to how Pool IDs are created, this is done with no storage accesses and costs little gas.
     */
    function _getPoolAddress(bytes32 poolId) internal pure returns (address) {
        // 12 byte logical shift left to remove the nonce and specialization setting. We don't need to mask,
        // since the logical shift already sets the upper bits to zero.
        return address(uint256(poolId) >> (12 * 8));
    }

    /**
     * @dev Returns the specialization setting of a Pool.
     *
     * Due to how Pool IDs are created, this is done with no storage accesses and costs little gas.
     */
    function _getPoolSpecialization(bytes32 poolId) internal pure returns (PoolSpecialization specialization) {
        // 10 byte logical shift left to remove the nonce, followed by a 2 byte mask to remove the address.
        uint256 value = uint256(poolId >> (10 * 8)) & (2**(2 * 8) - 1);

        // Casting a value into an enum results in a runtime check that reverts unless the value is within the enum's
        // range. Passing an invalid Pool ID to this function would then result in an obscure revert with no reason
        // string: we instead perform the check ourselves to help in error diagnosis.

        // There are three Pool specialization settings: general, minimal swap info and two tokens, which correspond to
        // values 0, 1 and 2.
        _require(value < 3, Errors.INVALID_POOL_ID);

        // Because we have checked that `value` is within the enum range, we can use assembly to skip the runtime check.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            specialization := value
        }
    }
}

File 40 of 45 : GeneralPoolsBalance.sol
// 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/BalancerErrors.sol";
import "../../lib/openzeppelin/EnumerableMap.sol";
import "../../lib/openzeppelin/IERC20.sol";

import "./BalanceAllocation.sol";

abstract contract GeneralPoolsBalance {
    using BalanceAllocation for bytes32;
    using EnumerableMap for EnumerableMap.IERC20ToBytes32Map;

    // Data for Pools with the General specialization setting
    //
    // These Pools use the IGeneralPool interface, which means the Vault must query the balance for *all* of their
    // tokens in every swap. If we kept a mapping of token to balance plus a set (array) of tokens, it'd be very gas
    // intensive to read all token addresses just to then do a lookup on the balance mapping.
    //
    // Instead, we use our customized EnumerableMap, which lets us read the N balances in N+1 storage accesses (one for
    // each token in the Pool), access the index of any 'token in' a single read (required for the IGeneralPool call),
    // and update an entry's value given its index.

    // Map of token -> balance pairs for each Pool with this specialization. Many functions rely on storage pointers to
    // a Pool's EnumerableMap to save gas when computing storage slots.
    mapping(bytes32 => EnumerableMap.IERC20ToBytes32Map) internal _generalPoolsBalances;

    /**
     * @dev Registers a list of tokens in a General Pool.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     *
     * Requirements:
     *
     * - `tokens` must not be registered in the Pool
     * - `tokens` must not contain duplicates
     */
    function _registerGeneralPoolTokens(bytes32 poolId, IERC20[] memory tokens) internal {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];

        for (uint256 i = 0; i < tokens.length; ++i) {
            // EnumerableMaps require an explicit initial value when creating a key-value pair: we use zero, the same
            // value that is found in uninitialized storage, which corresponds to an empty balance.
            bool added = poolBalances.set(tokens[i], 0);
            _require(added, Errors.TOKEN_ALREADY_REGISTERED);
        }
    }

    /**
     * @dev Deregisters a list of tokens in a General Pool.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     *
     * Requirements:
     *
     * - `tokens` must be registered in the Pool
     * - `tokens` must have zero balance in the Vault
     * - `tokens` must not contain duplicates
     */
    function _deregisterGeneralPoolTokens(bytes32 poolId, IERC20[] memory tokens) internal {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];

        for (uint256 i = 0; i < tokens.length; ++i) {
            IERC20 token = tokens[i];
            bytes32 currentBalance = _getGeneralPoolBalance(poolBalances, token);
            _require(currentBalance.isZero(), Errors.NONZERO_TOKEN_BALANCE);

            // We don't need to check remove's return value, since _getGeneralPoolBalance already checks that the token
            // was registered.
            poolBalances.remove(token);
        }
    }

    /**
     * @dev Sets the balances of a General Pool's tokens to `balances`.
     *
     * WARNING: this assumes `balances` has the same length and order as the Pool's tokens.
     */
    function _setGeneralPoolBalances(bytes32 poolId, bytes32[] memory balances) internal {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];

        for (uint256 i = 0; i < balances.length; ++i) {
            // Since we assume all balances are properly ordered, we can simply use `unchecked_setAt` to avoid one less
            // storage read per token.
            poolBalances.unchecked_setAt(i, balances[i]);
        }
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a General Pool from cash into managed.
     *
     * This function assumes `poolId` exists, corresponds to the General specialization setting, and that `token` is
     * registered for that Pool.
     */
    function _generalPoolCashToManaged(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateGeneralPoolBalance(poolId, token, BalanceAllocation.cashToManaged, amount);
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a General Pool from managed into cash.
     *
     * This function assumes `poolId` exists, corresponds to the General specialization setting, and that `token` is
     * registered for that Pool.
     */
    function _generalPoolManagedToCash(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateGeneralPoolBalance(poolId, token, BalanceAllocation.managedToCash, amount);
    }

    /**
     * @dev Sets `token`'s managed balance in a General Pool to `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the General specialization setting, and that `token` is
     * registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _setGeneralPoolManagedBalance(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal returns (int256) {
        return _updateGeneralPoolBalance(poolId, token, BalanceAllocation.setManaged, amount);
    }

    /**
     * @dev Sets `token`'s balance in a General Pool to the result of the `mutation` function when called with the
     * current balance and `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the General specialization setting, and that `token` is
     * registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _updateGeneralPoolBalance(
        bytes32 poolId,
        IERC20 token,
        function(bytes32, uint256) returns (bytes32) mutation,
        uint256 amount
    ) private returns (int256) {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];
        bytes32 currentBalance = _getGeneralPoolBalance(poolBalances, token);

        bytes32 newBalance = mutation(currentBalance, amount);
        poolBalances.set(token, newBalance);

        return newBalance.managedDelta(currentBalance);
    }

    /**
     * @dev Returns an array with all the tokens and balances in a General Pool. The order may change when tokens are
     * registered or deregistered.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     */
    function _getGeneralPoolTokens(bytes32 poolId)
        internal
        view
        returns (IERC20[] memory tokens, bytes32[] memory balances)
    {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];
        tokens = new IERC20[](poolBalances.length());
        balances = new bytes32[](tokens.length);

        for (uint256 i = 0; i < tokens.length; ++i) {
            // Because the iteration is bounded by `tokens.length`, which matches the EnumerableMap's length, we can use
            // `unchecked_at` as we know `i` is a valid token index, saving storage reads.
            (tokens[i], balances[i]) = poolBalances.unchecked_at(i);
        }
    }

    /**
     * @dev Returns the balance of a token in a General Pool.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     *
     * Requirements:
     *
     * - `token` must be registered in the Pool
     */
    function _getGeneralPoolBalance(bytes32 poolId, IERC20 token) internal view returns (bytes32) {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];
        return _getGeneralPoolBalance(poolBalances, token);
    }

    /**
     * @dev Same as `_getGeneralPoolBalance` but using a Pool's storage pointer, which saves gas in repeated reads and
     * writes.
     */
    function _getGeneralPoolBalance(EnumerableMap.IERC20ToBytes32Map storage poolBalances, IERC20 token)
        private
        view
        returns (bytes32)
    {
        return poolBalances.get(token, Errors.TOKEN_NOT_REGISTERED);
    }

    /**
     * @dev Returns true if `token` is registered in a General Pool.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     */
    function _isGeneralPoolTokenRegistered(bytes32 poolId, IERC20 token) internal view returns (bool) {
        EnumerableMap.IERC20ToBytes32Map storage poolBalances = _generalPoolsBalances[poolId];
        return poolBalances.contains(token);
    }
}

File 41 of 45 : MinimalSwapInfoPoolsBalance.sol
// 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/helpers/BalancerErrors.sol";
import "../../lib/openzeppelin/EnumerableSet.sol";
import "../../lib/openzeppelin/IERC20.sol";

import "./BalanceAllocation.sol";
import "../PoolRegistry.sol";

abstract contract MinimalSwapInfoPoolsBalance is PoolRegistry {
    using BalanceAllocation for bytes32;
    using EnumerableSet for EnumerableSet.AddressSet;

    // Data for Pools with the Minimal Swap Info specialization setting
    //
    // These Pools use the IMinimalSwapInfoPool interface, and so the Vault must read the balance of the two tokens
    // in the swap. The best solution is to use a mapping from token to balance, which lets us read or write any token's
    // balance in a single storage access.
    //
    // We also keep a set of registered tokens. Because tokens with non-zero balance are by definition registered, in
    // some balance getters we skip checking for token registration if a non-zero balance is found, saving gas by
    // performing a single read instead of two.

    mapping(bytes32 => mapping(IERC20 => bytes32)) internal _minimalSwapInfoPoolsBalances;
    mapping(bytes32 => EnumerableSet.AddressSet) internal _minimalSwapInfoPoolsTokens;

    /**
     * @dev Registers a list of tokens in a Minimal Swap Info Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Minimal Swap Info specialization setting.
     *
     * Requirements:
     *
     * - `tokens` must not be registered in the Pool
     * - `tokens` must not contain duplicates
     */
    function _registerMinimalSwapInfoPoolTokens(bytes32 poolId, IERC20[] memory tokens) internal {
        EnumerableSet.AddressSet storage poolTokens = _minimalSwapInfoPoolsTokens[poolId];

        for (uint256 i = 0; i < tokens.length; ++i) {
            bool added = poolTokens.add(address(tokens[i]));
            _require(added, Errors.TOKEN_ALREADY_REGISTERED);
            // Note that we don't initialize the balance mapping: the default value of zero corresponds to an empty
            // balance.
        }
    }

    /**
     * @dev Deregisters a list of tokens in a Minimal Swap Info Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Minimal Swap Info specialization setting.
     *
     * Requirements:
     *
     * - `tokens` must be registered in the Pool
     * - `tokens` must have zero balance in the Vault
     * - `tokens` must not contain duplicates
     */
    function _deregisterMinimalSwapInfoPoolTokens(bytes32 poolId, IERC20[] memory tokens) internal {
        EnumerableSet.AddressSet storage poolTokens = _minimalSwapInfoPoolsTokens[poolId];

        for (uint256 i = 0; i < tokens.length; ++i) {
            IERC20 token = tokens[i];
            _require(_minimalSwapInfoPoolsBalances[poolId][token].isZero(), Errors.NONZERO_TOKEN_BALANCE);

            // For consistency with other Pool specialization settings, we explicitly reset the balance (which may have
            // a non-zero last change block).
            delete _minimalSwapInfoPoolsBalances[poolId][token];

            bool removed = poolTokens.remove(address(token));
            _require(removed, Errors.TOKEN_NOT_REGISTERED);
        }
    }

    /**
     * @dev Sets the balances of a Minimal Swap Info Pool's tokens to `balances`.
     *
     * WARNING: this assumes `balances` has the same length and order as the Pool's tokens.
     */
    function _setMinimalSwapInfoPoolBalances(
        bytes32 poolId,
        IERC20[] memory tokens,
        bytes32[] memory balances
    ) internal {
        for (uint256 i = 0; i < tokens.length; ++i) {
            _minimalSwapInfoPoolsBalances[poolId][tokens[i]] = balances[i];
        }
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a Minimal Swap Info Pool from cash into managed.
     *
     * This function assumes `poolId` exists, corresponds to the Minimal Swap Info specialization setting, and that
     * `token` is registered for that Pool.
     */
    function _minimalSwapInfoPoolCashToManaged(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateMinimalSwapInfoPoolBalance(poolId, token, BalanceAllocation.cashToManaged, amount);
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a Minimal Swap Info Pool from managed into cash.
     *
     * This function assumes `poolId` exists, corresponds to the Minimal Swap Info specialization setting, and that
     * `token` is registered for that Pool.
     */
    function _minimalSwapInfoPoolManagedToCash(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateMinimalSwapInfoPoolBalance(poolId, token, BalanceAllocation.managedToCash, amount);
    }

    /**
     * @dev Sets `token`'s managed balance in a Minimal Swap Info Pool to `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the Minimal Swap Info specialization setting, and that
     * `token` is registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _setMinimalSwapInfoPoolManagedBalance(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal returns (int256) {
        return _updateMinimalSwapInfoPoolBalance(poolId, token, BalanceAllocation.setManaged, amount);
    }

    /**
     * @dev Sets `token`'s balance in a Minimal Swap Info Pool to the result of the `mutation` function when called with
     * the current balance and `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the Minimal Swap Info specialization setting, and that
     * `token` is registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _updateMinimalSwapInfoPoolBalance(
        bytes32 poolId,
        IERC20 token,
        function(bytes32, uint256) returns (bytes32) mutation,
        uint256 amount
    ) internal returns (int256) {
        bytes32 currentBalance = _getMinimalSwapInfoPoolBalance(poolId, token);

        bytes32 newBalance = mutation(currentBalance, amount);
        _minimalSwapInfoPoolsBalances[poolId][token] = newBalance;

        return newBalance.managedDelta(currentBalance);
    }

    /**
     * @dev Returns an array with all the tokens and balances in a Minimal Swap Info Pool. The order may change when
     * tokens are registered or deregistered.
     *
     * This function assumes `poolId` exists and corresponds to the Minimal Swap Info specialization setting.
     */
    function _getMinimalSwapInfoPoolTokens(bytes32 poolId)
        internal
        view
        returns (IERC20[] memory tokens, bytes32[] memory balances)
    {
        EnumerableSet.AddressSet storage poolTokens = _minimalSwapInfoPoolsTokens[poolId];
        tokens = new IERC20[](poolTokens.length());
        balances = new bytes32[](tokens.length);

        for (uint256 i = 0; i < tokens.length; ++i) {
            // Because the iteration is bounded by `tokens.length`, which matches the EnumerableSet's length, we can use
            // `unchecked_at` as we know `i` is a valid token index, saving storage reads.
            IERC20 token = IERC20(poolTokens.unchecked_at(i));
            tokens[i] = token;
            balances[i] = _minimalSwapInfoPoolsBalances[poolId][token];
        }
    }

    /**
     * @dev Returns the balance of a token in a Minimal Swap Info Pool.
     *
     * Requirements:
     *
     * - `poolId` must be a Minimal Swap Info Pool
     * - `token` must be registered in the Pool
     */
    function _getMinimalSwapInfoPoolBalance(bytes32 poolId, IERC20 token) internal view returns (bytes32) {
        bytes32 balance = _minimalSwapInfoPoolsBalances[poolId][token];

        // A non-zero balance guarantees that the token is registered. If zero, we manually check if the token is
        // registered in the Pool. Token registration implies that the Pool is registered as well, which lets us save
        // gas by not performing the check.
        bool tokenRegistered = balance.isNotZero() || _minimalSwapInfoPoolsTokens[poolId].contains(address(token));

        if (!tokenRegistered) {
            // The token might not be registered because the Pool itself is not registered. We check this to provide a
            // more accurate revert reason.
            _ensureRegisteredPool(poolId);
            _revert(Errors.TOKEN_NOT_REGISTERED);
        }

        return balance;
    }

    /**
     * @dev Returns true if `token` is registered in a Minimal Swap Info Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Minimal Swap Info specialization setting.
     */
    function _isMinimalSwapInfoPoolTokenRegistered(bytes32 poolId, IERC20 token) internal view returns (bool) {
        EnumerableSet.AddressSet storage poolTokens = _minimalSwapInfoPoolsTokens[poolId];
        return poolTokens.contains(address(token));
    }
}

File 42 of 45 : TwoTokenPoolsBalance.sol
// 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/helpers/BalancerErrors.sol";
import "../../lib/openzeppelin/IERC20.sol";

import "./BalanceAllocation.sol";
import "../PoolRegistry.sol";

abstract contract TwoTokenPoolsBalance is PoolRegistry {
    using BalanceAllocation for bytes32;

    // Data for Pools with the Two Token specialization setting
    //
    // These are similar to the Minimal Swap Info Pool case (because the Pool only has two tokens, and therefore there
    // are only two balances to read), but there's a key difference in how data is stored. Keeping a set makes little
    // sense, as it will only ever hold two tokens, so we can just store those two directly.
    //
    // The gas savings associated with using these Pools come from how token balances are stored: cash amounts for token
    // A and token B are packed together, as are managed amounts. Because only cash changes in a swap, there's no need
    // to write to this second storage slot. A single last change block number for both tokens is stored with the packed
    // cash fields.

    struct TwoTokenPoolBalances {
        bytes32 sharedCash;
        bytes32 sharedManaged;
    }

    // We could just keep a mapping from Pool ID to TwoTokenSharedBalances, but there's an issue: we wouldn't know to
    // which tokens those balances correspond. This would mean having to also check which are registered with the Pool.
    //
    // What we do instead to save those storage reads is keep a nested mapping from the token pair hash to the balances
    // struct. The Pool only has two tokens, so only a single entry of this mapping is set (the one that corresponds to
    // that pair's hash).
    //
    // This has the trade-off of making Vault code that interacts with these Pools cumbersome: both balances must be
    // accessed at the same time by using both token addresses, and some logic is needed to determine how the pair hash
    // is computed. We do this by sorting the tokens, calling the token with the lowest numerical address value token A,
    // and the other one token B. In functions where the token arguments could be either A or B, we use X and Y instead.
    //
    // If users query a token pair containing an unregistered token, the Pool will generate a hash for a mapping entry
    // that was not set, and return zero balances. Non-zero balances are only possible if both tokens in the pair
    // are registered with the Pool, which means we don't have to check the TwoTokenPoolTokens struct, and can save
    // storage reads.

    struct TwoTokenPoolTokens {
        IERC20 tokenA;
        IERC20 tokenB;
        mapping(bytes32 => TwoTokenPoolBalances) balances;
    }

    mapping(bytes32 => TwoTokenPoolTokens) private _twoTokenPoolTokens;

    /**
     * @dev Registers tokens in a Two Token Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Two Token specialization setting.
     *
     * Requirements:
     *
     * - `tokenX` and `tokenY` must not be the same
     * - The tokens must be ordered: tokenX < tokenY
     */
    function _registerTwoTokenPoolTokens(
        bytes32 poolId,
        IERC20 tokenX,
        IERC20 tokenY
    ) internal {
        // Not technically true since we didn't register yet, but this is consistent with the error messages of other
        // specialization settings.
        _require(tokenX != tokenY, Errors.TOKEN_ALREADY_REGISTERED);

        _require(tokenX < tokenY, Errors.UNSORTED_TOKENS);

        // A Two Token Pool with no registered tokens is identified by having zero addresses for tokens A and B.
        TwoTokenPoolTokens storage poolTokens = _twoTokenPoolTokens[poolId];
        _require(poolTokens.tokenA == IERC20(0) && poolTokens.tokenB == IERC20(0), Errors.TOKENS_ALREADY_SET);

        // Since tokenX < tokenY, tokenX is A and tokenY is B
        poolTokens.tokenA = tokenX;
        poolTokens.tokenB = tokenY;

        // Note that we don't initialize the balance mapping: the default value of zero corresponds to an empty
        // balance.
    }

    /**
     * @dev Deregisters tokens in a Two Token Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Two Token specialization setting.
     *
     * Requirements:
     *
     * - `tokenX` and `tokenY` must be registered in the Pool
     * - both tokens must have zero balance in the Vault
     */
    function _deregisterTwoTokenPoolTokens(
        bytes32 poolId,
        IERC20 tokenX,
        IERC20 tokenY
    ) internal {
        (
            bytes32 balanceA,
            bytes32 balanceB,
            TwoTokenPoolBalances storage poolBalances
        ) = _getTwoTokenPoolSharedBalances(poolId, tokenX, tokenY);

        _require(balanceA.isZero() && balanceB.isZero(), Errors.NONZERO_TOKEN_BALANCE);

        delete _twoTokenPoolTokens[poolId];

        // For consistency with other Pool specialization settings, we explicitly reset the packed cash field (which may
        // have a non-zero last change block).
        delete poolBalances.sharedCash;
    }

    /**
     * @dev Sets the cash balances of a Two Token Pool's tokens.
     *
     * WARNING: this assumes `tokenA` and `tokenB` are the Pool's two registered tokens, and are in the correct order.
     */
    function _setTwoTokenPoolCashBalances(
        bytes32 poolId,
        IERC20 tokenA,
        bytes32 balanceA,
        IERC20 tokenB,
        bytes32 balanceB
    ) internal {
        bytes32 pairHash = _getTwoTokenPairHash(tokenA, tokenB);
        TwoTokenPoolBalances storage poolBalances = _twoTokenPoolTokens[poolId].balances[pairHash];
        poolBalances.sharedCash = BalanceAllocation.toSharedCash(balanceA, balanceB);
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a Two Token Pool from cash into managed.
     *
     * This function assumes `poolId` exists, corresponds to the Two Token specialization setting, and that `token` is
     * registered for that Pool.
     */
    function _twoTokenPoolCashToManaged(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateTwoTokenPoolSharedBalance(poolId, token, BalanceAllocation.cashToManaged, amount);
    }

    /**
     * @dev Transforms `amount` of `token`'s balance in a Two Token Pool from managed into cash.
     *
     * This function assumes `poolId` exists, corresponds to the Two Token specialization setting, and that `token` is
     * registered for that Pool.
     */
    function _twoTokenPoolManagedToCash(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal {
        _updateTwoTokenPoolSharedBalance(poolId, token, BalanceAllocation.managedToCash, amount);
    }

    /**
     * @dev Sets `token`'s managed balance in a Two Token Pool to `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the Two Token specialization setting, and that `token` is
     * registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _setTwoTokenPoolManagedBalance(
        bytes32 poolId,
        IERC20 token,
        uint256 amount
    ) internal returns (int256) {
        return _updateTwoTokenPoolSharedBalance(poolId, token, BalanceAllocation.setManaged, amount);
    }

    /**
     * @dev Sets `token`'s balance in a Two Token Pool to the result of the `mutation` function when called with
     * the current balance and `amount`.
     *
     * This function assumes `poolId` exists, corresponds to the Two Token specialization setting, and that `token` is
     * registered for that Pool.
     *
     * Returns the managed balance delta as a result of this call.
     */
    function _updateTwoTokenPoolSharedBalance(
        bytes32 poolId,
        IERC20 token,
        function(bytes32, uint256) returns (bytes32) mutation,
        uint256 amount
    ) private returns (int256) {
        (
            TwoTokenPoolBalances storage balances,
            IERC20 tokenA,
            bytes32 balanceA,
            ,
            bytes32 balanceB
        ) = _getTwoTokenPoolBalances(poolId);

        int256 delta;
        if (token == tokenA) {
            bytes32 newBalance = mutation(balanceA, amount);
            delta = newBalance.managedDelta(balanceA);
            balanceA = newBalance;
        } else {
            // token == tokenB
            bytes32 newBalance = mutation(balanceB, amount);
            delta = newBalance.managedDelta(balanceB);
            balanceB = newBalance;
        }

        balances.sharedCash = BalanceAllocation.toSharedCash(balanceA, balanceB);
        balances.sharedManaged = BalanceAllocation.toSharedManaged(balanceA, balanceB);

        return delta;
    }

    /*
     * @dev Returns an array with all the tokens and balances in a Two Token Pool. The order may change when
     * tokens are registered or deregistered.
     *
     * This function assumes `poolId` exists and corresponds to the Two Token specialization setting.
     */
    function _getTwoTokenPoolTokens(bytes32 poolId)
        internal
        view
        returns (IERC20[] memory tokens, bytes32[] memory balances)
    {
        (, IERC20 tokenA, bytes32 balanceA, IERC20 tokenB, bytes32 balanceB) = _getTwoTokenPoolBalances(poolId);

        // Both tokens will either be zero (if unregistered) or non-zero (if registered), but we keep the full check for
        // clarity.
        if (tokenA == IERC20(0) || tokenB == IERC20(0)) {
            return (new IERC20[](0), new bytes32[](0));
        }

        // Note that functions relying on this getter expect tokens to be properly ordered, so we use the (A, B)
        // ordering.

        tokens = new IERC20[](2);
        tokens[0] = tokenA;
        tokens[1] = tokenB;

        balances = new bytes32[](2);
        balances[0] = balanceA;
        balances[1] = balanceB;
    }

    /**
     * @dev Same as `_getTwoTokenPoolTokens`, except it returns the two tokens and balances directly instead of using
     * an array, as well as a storage pointer to the `TwoTokenPoolBalances` struct, which can be used to update it
     * without having to recompute the pair hash and storage slot.
     */
    function _getTwoTokenPoolBalances(bytes32 poolId)
        private
        view
        returns (
            TwoTokenPoolBalances storage poolBalances,
            IERC20 tokenA,
            bytes32 balanceA,
            IERC20 tokenB,
            bytes32 balanceB
        )
    {
        TwoTokenPoolTokens storage poolTokens = _twoTokenPoolTokens[poolId];
        tokenA = poolTokens.tokenA;
        tokenB = poolTokens.tokenB;

        bytes32 pairHash = _getTwoTokenPairHash(tokenA, tokenB);
        poolBalances = poolTokens.balances[pairHash];

        bytes32 sharedCash = poolBalances.sharedCash;
        bytes32 sharedManaged = poolBalances.sharedManaged;

        balanceA = BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged);
        balanceB = BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged);
    }

    /**
     * @dev Returns the balance of a token in a Two Token Pool.
     *
     * This function assumes `poolId` exists and corresponds to the General specialization setting.
     *
     * This function is convenient but not particularly gas efficient, and should be avoided during gas-sensitive
     * operations, such as swaps. For those, _getTwoTokenPoolSharedBalances provides a more flexible interface.
     *
     * Requirements:
     *
     * - `token` must be registered in the Pool
     */
    function _getTwoTokenPoolBalance(bytes32 poolId, IERC20 token) internal view returns (bytes32) {
        // We can't just read the balance of token, because we need to know the full pair in order to compute the pair
        // hash and access the balance mapping. We therefore rely on `_getTwoTokenPoolBalances`.
        (, IERC20 tokenA, bytes32 balanceA, IERC20 tokenB, bytes32 balanceB) = _getTwoTokenPoolBalances(poolId);

        if (token == tokenA) {
            return balanceA;
        } else if (token == tokenB) {
            return balanceB;
        } else {
            _revert(Errors.TOKEN_NOT_REGISTERED);
        }
    }

    /**
     * @dev Returns the balance of the two tokens in a Two Token Pool.
     *
     * The returned balances are those of token A and token B, where token A is the lowest of token X and token Y, and
     * token B the other.
     *
     * This function also returns a storage pointer to the TwoTokenPoolBalances struct associated with the token pair,
     * which can be used to update it without having to recompute the pair hash and storage slot.
     *
     * Requirements:
     *
     * - `poolId` must be a Minimal Swap Info Pool
     * - `tokenX` and `tokenY` must be registered in the Pool
     */
    function _getTwoTokenPoolSharedBalances(
        bytes32 poolId,
        IERC20 tokenX,
        IERC20 tokenY
    )
        internal
        view
        returns (
            bytes32 balanceA,
            bytes32 balanceB,
            TwoTokenPoolBalances storage poolBalances
        )
    {
        (IERC20 tokenA, IERC20 tokenB) = _sortTwoTokens(tokenX, tokenY);
        bytes32 pairHash = _getTwoTokenPairHash(tokenA, tokenB);

        poolBalances = _twoTokenPoolTokens[poolId].balances[pairHash];

        // Because we're reading balances using the pair hash, if either token X or token Y is not registered then
        // *both* balance entries will be zero.
        bytes32 sharedCash = poolBalances.sharedCash;
        bytes32 sharedManaged = poolBalances.sharedManaged;

        // A non-zero balance guarantees that both tokens are registered. If zero, we manually check whether each
        // token is registered in the Pool. Token registration implies that the Pool is registered as well, which
        // lets us save gas by not performing the check.
        bool tokensRegistered = sharedCash.isNotZero() ||
            sharedManaged.isNotZero() ||
            (_isTwoTokenPoolTokenRegistered(poolId, tokenA) && _isTwoTokenPoolTokenRegistered(poolId, tokenB));

        if (!tokensRegistered) {
            // The tokens might not be registered because the Pool itself is not registered. We check this to provide a
            // more accurate revert reason.
            _ensureRegisteredPool(poolId);
            _revert(Errors.TOKEN_NOT_REGISTERED);
        }

        balanceA = BalanceAllocation.fromSharedToBalanceA(sharedCash, sharedManaged);
        balanceB = BalanceAllocation.fromSharedToBalanceB(sharedCash, sharedManaged);
    }

    /**
     * @dev Returns true if `token` is registered in a Two Token Pool.
     *
     * This function assumes `poolId` exists and corresponds to the Two Token specialization setting.
     */
    function _isTwoTokenPoolTokenRegistered(bytes32 poolId, IERC20 token) internal view returns (bool) {
        TwoTokenPoolTokens storage poolTokens = _twoTokenPoolTokens[poolId];

        // The zero address can never be a registered token.
        return (token == poolTokens.tokenA || token == poolTokens.tokenB) && token != IERC20(0);
    }

    /**
     * @dev Returns the hash associated with a given token pair.
     */
    function _getTwoTokenPairHash(IERC20 tokenA, IERC20 tokenB) private pure returns (bytes32) {
        return keccak256(abi.encodePacked(tokenA, tokenB));
    }

    /**
     * @dev Sorts two tokens in ascending order, returning them as a (tokenA, tokenB) tuple.
     */
    function _sortTwoTokens(IERC20 tokenX, IERC20 tokenY) private pure returns (IERC20, IERC20) {
        return tokenX < tokenY ? (tokenX, tokenY) : (tokenY, tokenX);
    }
}

File 43 of 45 : AssetTransfersHandler.sol
// 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/Math.sol";
import "../lib/helpers/BalancerErrors.sol";
import "../lib/openzeppelin/IERC20.sol";
import "../lib/helpers/AssetHelpers.sol";
import "../lib/openzeppelin/SafeERC20.sol";
import "../lib/openzeppelin/Address.sol";

import "./interfaces/IWETH.sol";
import "./interfaces/IAsset.sol";
import "./interfaces/IVault.sol";

abstract contract AssetTransfersHandler is AssetHelpers {
    using SafeERC20 for IERC20;
    using Address for address payable;

    /**
     * @dev Receives `amount` of `asset` from `sender`. If `fromInternalBalance` is true, it first withdraws as much
     * as possible from Internal Balance, then transfers any remaining amount.
     *
     * If `asset` is ETH, `fromInternalBalance` must be false (as ETH cannot be held as internal balance), and the funds
     * will be wrapped into WETH.
     *
     * WARNING: this function does not check that the contract caller has actually supplied any ETH - it is up to the
     * caller of this function to check that this is true to prevent the Vault from using its own ETH (though the Vault
     * typically doesn't hold any).
     */
    function _receiveAsset(
        IAsset asset,
        uint256 amount,
        address sender,
        bool fromInternalBalance
    ) internal {
        if (amount == 0) {
            return;
        }

        if (_isETH(asset)) {
            _require(!fromInternalBalance, Errors.INVALID_ETH_INTERNAL_BALANCE);

            // The ETH amount to receive is deposited into the WETH contract, which will in turn mint WETH for
            // the Vault at a 1:1 ratio.

            // A check for this condition is also introduced by the compiler, but this one provides a revert reason.
            // Note we're checking for the Vault's total balance, *not* ETH sent in this transaction.
            _require(address(this).balance >= amount, Errors.INSUFFICIENT_ETH);
            _WETH().deposit{ value: amount }();
        } else {
            IERC20 token = _asIERC20(asset);

            if (fromInternalBalance) {
                // We take as many tokens from Internal Balance as possible: any remaining amounts will be transferred.
                uint256 deductedBalance = _decreaseInternalBalance(sender, token, amount, true);
                // Because `deductedBalance` will be always the lesser of the current internal balance
                // and the amount to decrease, it is safe to perform unchecked arithmetic.
                amount -= deductedBalance;
            }

            if (amount > 0) {
                token.safeTransferFrom(sender, address(this), amount);
            }
        }
    }

    /**
     * @dev Sends `amount` of `asset` to `recipient`. If `toInternalBalance` is true, the asset is deposited as Internal
     * Balance instead of being transferred.
     *
     * If `asset` is ETH, `toInternalBalance` must be false (as ETH cannot be held as internal balance), and the funds
     * are instead sent directly after unwrapping WETH.
     */
    function _sendAsset(
        IAsset asset,
        uint256 amount,
        address payable recipient,
        bool toInternalBalance
    ) internal {
        if (amount == 0) {
            return;
        }

        if (_isETH(asset)) {
            // Sending ETH is not as involved as receiving it: the only special behavior is it cannot be
            // deposited to Internal Balance.
            _require(!toInternalBalance, Errors.INVALID_ETH_INTERNAL_BALANCE);

            // First, the Vault withdraws deposited ETH from the WETH contract, by burning the same amount of WETH
            // from the Vault. This receipt will be handled by the Vault's `receive`.
            _WETH().withdraw(amount);

            // Then, the withdrawn ETH is sent to the recipient.
            recipient.sendValue(amount);
        } else {
            IERC20 token = _asIERC20(asset);
            if (toInternalBalance) {
                _increaseInternalBalance(recipient, token, amount);
            } else {
                token.safeTransfer(recipient, amount);
            }
        }
    }

    /**
     * @dev Returns excess ETH back to the contract caller, assuming `amountUsed` has been spent. Reverts
     * if the caller sent less ETH than `amountUsed`.
     *
     * Because the caller might not know exactly how much ETH a Vault action will require, they may send extra.
     * Note that this excess value is returned *to the contract caller* (msg.sender). If caller and e.g. swap sender are
     * not the same (because the caller is a relayer for the sender), then it is up to the caller to manage this
     * returned ETH.
     */
    function _handleRemainingEth(uint256 amountUsed) internal {
        _require(msg.value >= amountUsed, Errors.INSUFFICIENT_ETH);

        uint256 excess = msg.value - amountUsed;
        if (excess > 0) {
            msg.sender.sendValue(excess);
        }
    }

    /**
     * @dev Enables the Vault to receive ETH. This is required for it to be able to unwrap WETH, which sends ETH to the
     * caller.
     *
     * Any ETH sent to the Vault outside of the WETH unwrapping mechanism would be forever locked inside the Vault, so
     * we prevent that from happening. Other mechanisms used to send ETH to the Vault (such as being the recipient of an
     * ETH swap, Pool exit or withdrawal, contract self-destruction, or receiving the block mining reward) will result
     * in locked funds, but are not otherwise a security or soundness issue. This check only exists as an attempt to
     * prevent user error.
     */
    receive() external payable {
        _require(msg.sender == address(_WETH()), Errors.ETH_TRANSFER);
    }

    // This contract uses virtual internal functions instead of inheriting from the modules that implement them (in
    // this case UserBalance) in order to decouple it from the rest of the system and enable standalone testing by
    // implementing these with mocks.

    function _increaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount
    ) internal virtual;

    function _decreaseInternalBalance(
        address account,
        IERC20 token,
        uint256 amount,
        bool capped
    ) internal virtual returns (uint256);
}

File 44 of 45 : AssetHelpers.sol
// 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 "../../vault/interfaces/IAsset.sol";
import "../../vault/interfaces/IWETH.sol";

abstract contract AssetHelpers {
    // solhint-disable-next-line var-name-mixedcase
    IWETH private immutable _weth;

    // Sentinel value used to indicate WETH with wrapping/unwrapping semantics. The zero address is a good choice for
    // multiple reasons: it is cheap to pass as a calldata argument, it is a known invalid token and non-contract, and
    // it is an address Pools cannot register as a token.
    address private constant _ETH = address(0);

    constructor(IWETH weth) {
        _weth = weth;
    }

    // solhint-disable-next-line func-name-mixedcase
    function _WETH() internal view returns (IWETH) {
        return _weth;
    }

    /**
     * @dev Returns true if `asset` is the sentinel value that represents ETH.
     */
    function _isETH(IAsset asset) internal pure returns (bool) {
        return address(asset) == _ETH;
    }

    /**
     * @dev Translates `asset` into an equivalent IERC20 token address. If `asset` represents ETH, it will be translated
     * to the WETH contract.
     */
    function _translateToIERC20(IAsset asset) internal view returns (IERC20) {
        return _isETH(asset) ? _WETH() : _asIERC20(asset);
    }

    /**
     * @dev Same as `_translateToIERC20(IAsset)`, but for an entire array.
     */
    function _translateToIERC20(IAsset[] memory assets) internal view returns (IERC20[] memory) {
        IERC20[] memory tokens = new IERC20[](assets.length);
        for (uint256 i = 0; i < assets.length; ++i) {
            tokens[i] = _translateToIERC20(assets[i]);
        }
        return tokens;
    }

    /**
     * @dev Interprets `asset` as an IERC20 token. This function should only be called on `asset` if `_isETH` previously
     * returned false for it, that is, if `asset` is guaranteed not to be the ETH sentinel value.
     */
    function _asIERC20(IAsset asset) internal pure returns (IERC20) {
        return IERC20(address(asset));
    }
}

File 45 of 45 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../helpers/BalancerErrors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        _require(address(this).balance >= amount, Errors.ADDRESS_INSUFFICIENT_BALANCE);

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        _require(success, Errors.ADDRESS_CANNOT_SEND_VALUE);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1500
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IAuthorizer","name":"authorizer","type":"address"},{"internalType":"contract IWETH","name":"weth","type":"address"},{"internalType":"uint256","name":"pauseWindowDuration","type":"uint256"},{"internalType":"uint256","name":"bufferPeriodDuration","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IAuthorizer","name":"newAuthorizer","type":"address"}],"name":"AuthorizerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExternalBalanceTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IFlashLoanRecipient","name":"recipient","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"FlashLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"int256","name":"delta","type":"int256"}],"name":"InternalBalanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"PausedStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"int256[]","name":"deltas","type":"int256[]"},{"indexed":false,"internalType":"uint256[]","name":"protocolFeeAmounts","type":"uint256[]"}],"name":"PoolBalanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"assetManager","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"int256","name":"cashDelta","type":"int256"},{"indexed":false,"internalType":"int256","name":"managedDelta","type":"int256"}],"name":"PoolBalanceManaged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"poolAddress","type":"address"},{"indexed":false,"internalType":"enum IVault.PoolSpecialization","name":"specialization","type":"uint8"}],"name":"PoolRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"RelayerApprovalChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":true,"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"TokensDeregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"poolId","type":"bytes32"},{"indexed":false,"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"assetManagers","type":"address[]"}],"name":"TokensRegistered","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IVault.SwapKind","name":"kind","type":"uint8"},{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint256","name":"assetInIndex","type":"uint256"},{"internalType":"uint256","name":"assetOutIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct IVault.BatchSwapStep[]","name":"swaps","type":"tuple[]"},{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"bool","name":"toInternalBalance","type":"bool"}],"internalType":"struct IVault.FundManagement","name":"funds","type":"tuple"},{"internalType":"int256[]","name":"limits","type":"int256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"batchSwap","outputs":[{"internalType":"int256[]","name":"assetDeltas","type":"int256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"deregisterTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"},{"components":[{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"minAmountsOut","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bool","name":"toInternalBalance","type":"bool"}],"internalType":"struct IVault.ExitPoolRequest","name":"request","type":"tuple"}],"name":"exitPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFlashLoanRecipient","name":"recipient","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"}],"name":"flashLoan","outputs":[],"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":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"getInternalBalance","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNextNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"internalType":"bytes32","name":"poolId","type":"bytes32"}],"name":"getPool","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"enum IVault.PoolSpecialization","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"getPoolTokenInfo","outputs":[{"internalType":"uint256","name":"cash","type":"uint256"},{"internalType":"uint256","name":"managed","type":"uint256"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"},{"internalType":"address","name":"assetManager","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"}],"name":"getPoolTokens","outputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"},{"internalType":"uint256","name":"lastChangeBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProtocolFeesCollector","outputs":[{"internalType":"contract ProtocolFeesCollector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"relayer","type":"address"}],"name":"hasApprovedRelayer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"internalType":"uint256[]","name":"maxAmountsIn","type":"uint256[]"},{"internalType":"bytes","name":"userData","type":"bytes"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"}],"internalType":"struct IVault.JoinPoolRequest","name":"request","type":"tuple"}],"name":"joinPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IVault.PoolBalanceOpKind","name":"kind","type":"uint8"},{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IVault.PoolBalanceOp[]","name":"ops","type":"tuple[]"}],"name":"managePoolBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"enum IVault.UserBalanceOpKind","name":"kind","type":"uint8"},{"internalType":"contract IAsset","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct IVault.UserBalanceOp[]","name":"ops","type":"tuple[]"}],"name":"manageUserBalance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"enum IVault.SwapKind","name":"kind","type":"uint8"},{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint256","name":"assetInIndex","type":"uint256"},{"internalType":"uint256","name":"assetOutIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct IVault.BatchSwapStep[]","name":"swaps","type":"tuple[]"},{"internalType":"contract IAsset[]","name":"assets","type":"address[]"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"bool","name":"toInternalBalance","type":"bool"}],"internalType":"struct IVault.FundManagement","name":"funds","type":"tuple"}],"name":"queryBatchSwap","outputs":[{"internalType":"int256[]","name":"","type":"int256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IVault.PoolSpecialization","name":"specialization","type":"uint8"}],"name":"registerPool","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"assetManagers","type":"address[]"}],"name":"registerTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IAuthorizer","name":"newAuthorizer","type":"address"}],"name":"setAuthorizer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setRelayerApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"enum IVault.SwapKind","name":"kind","type":"uint8"},{"internalType":"contract IAsset","name":"assetIn","type":"address"},{"internalType":"contract IAsset","name":"assetOut","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct IVault.SingleSwap","name":"singleSwap","type":"tuple"},{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bool","name":"fromInternalBalance","type":"bool"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"bool","name":"toInternalBalance","type":"bool"}],"internalType":"struct IVault.FundManagement","name":"funds","type":"tuple"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountCalculated","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101806040523480156200001257600080fd5b5060405162006ed638038062006ed6833981016040819052620000359162000253565b8382826040518060400160405280601181526020017010985b185b98d95c88158c8815985d5b1d607a1b81525080604051806040016040528060018152602001603160f81b815250306001600160a01b031660001b89806001600160a01b03166080816001600160a01b031660601b815250505030604051620000b89062000245565b620000c491906200029f565b604051809103906000f080158015620000e1573d6000803e3d6000fd5b5060601b6001600160601b03191660a052600160005560c052815160209283012060e052805191012061010052507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f61012052620001486276a70083111561019462000181565b6200015c62278d0082111561019562000181565b429091016101408190520161016052620001768162000196565b5050505050620002cc565b8162000192576200019281620001f2565b5050565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b62461bcd60e51b6000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b610be680620062f083390190565b6000806000806080858703121562000269578384fd5b84516200027681620002b3565b60208601519094506200028981620002b3565b6040860151606090960151949790965092505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620002c957600080fd5b50565b60805160601c60a05160601c60c05160e05161010051610120516101405161016051615fc06200033060003980611aed525080611ac952508061289f5250806128e15250806128c05250806110fd5250806113b15250806105285250615fc06000f3fe6080604052600436106101a55760003560e01c8063945bcec9116100e1578063e6c460921161008a578063f84d066e11610064578063f84d066e1461048a578063f94d4668146104aa578063fa6e671d146104d9578063fec90d72146104f9576101d3565b8063e6c4609214610427578063ed24911d14610447578063f6c009271461045c576101d3565b8063b05f8e48116100bb578063b05f8e48146103cf578063b95cac28146103ff578063d2946c2b14610412576101d3565b8063945bcec914610385578063aaabadc514610398578063ad5c4648146103ba576101d3565b806352bbbe291161014e5780637d3aeb96116101285780637d3aeb9614610305578063851c1bb3146103255780638bdb39131461034557806390193b7c14610365576101d3565b806352bbbe29146102b25780635c38449e146102c557806366a9c7d2146102e5576101d3565b80630f5a6efa1161017f5780630f5a6efa1461024157806316c38b3c1461026e5780631c0de0511461028e576101d3565b8063058a628f146101d857806309b2760f146101f85780630e8e3e841461022e576101d3565b366101d3576101d16101b5610526565b6001600160a01b0316336001600160a01b03161461020661054b565b005b600080fd5b3480156101e457600080fd5b506101d16101f3366004615157565b61055d565b34801561020457600080fd5b506102186102133660046156e6565b610581565b6040516102259190615d3e565b60405180910390f35b6101d161023c36600461531e565b610634565b34801561024d57600080fd5b5061026161025c3660046151f5565b610770565b6040516102259190615d08565b34801561027a57600080fd5b506101d161028936600461545c565b610806565b34801561029a57600080fd5b506102a361081f565b60405161022593929190615d26565b6102186102c036600461588f565b610848565b3480156102d157600080fd5b506101d16102e036600461565b565b6109e9565b3480156102f157600080fd5b506101d1610300366004615545565b610e06565b34801561031157600080fd5b506101d1610320366004615516565b610fa5565b34801561033157600080fd5b50610218610340366004615633565b6110f9565b34801561035157600080fd5b506101d16103603660046154ac565b61114b565b34801561037157600080fd5b50610218610380366004615157565b611161565b610261610393366004615786565b61117c565b3480156103a457600080fd5b506103ad6112b0565b6040516102259190615b63565b3480156103c657600080fd5b506103ad6112c4565b3480156103db57600080fd5b506103ef6103ea36600461560f565b6112d3565b6040516102259493929190615eb9565b6101d161040d3660046154ac565b611396565b34801561041e57600080fd5b506103ad6113af565b34801561043357600080fd5b506101d1610442366004615243565b6113d3565b34801561045357600080fd5b506102186114ef565b34801561046857600080fd5b5061047c610477366004615494565b6114f9565b604051610225929190615b9b565b34801561049657600080fd5b506102616104a5366004615702565b611523565b3480156104b657600080fd5b506104ca6104c5366004615494565b611620565b60405161022593929190615cd2565b3480156104e557600080fd5b506101d16104f43660046151ab565b611654565b34801561050557600080fd5b50610519610514366004615173565b6116e6565b6040516102259190615d1b565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b8161055957610559816116fb565b5050565b610565611768565b61056d611781565b610576816117af565b61057e611822565b50565b600061058b611768565b610593611829565b60006105a2338460065461183e565b6000818152600560205260409020549091506105c49060ff16156101f461054b565b60008181526005602052604090819020805460ff1916600190811790915560068054909101905551339082907f3c13bc30b8e878c53fd2a36b679409c073afd75950be43d8858768e956fbc20e9061061d908790615e3a565b60405180910390a3905061062f611822565b919050565b61063c611768565b6000806000805b845181101561075b5760008060008060006106718a878151811061066357fe5b60200260200101518961187d565b9c50939850919650945092509050600185600381111561068d57fe5b14156106a45761069f848383866118f5565b61074a565b866106b6576106b1611829565b600196505b60008560038111156106c457fe5b14156106f5576106d684838386611918565b6106df84611938565b1561069f576106ee8984611945565b985061074a565b61070a61070185611938565b1561020761054b565b600061071585610548565b9050600286600381111561072557fe5b141561073c5761073781848487611957565b610748565b61074881848487611970565b505b505060019093019250610643915050565b50610765836119de565b50505061057e611822565b6060815167ffffffffffffffff8111801561078a57600080fd5b506040519080825280602002602001820160405280156107b4578160200160208202803683370190505b50905060005b82518110156107ff576107e0848483815181106107d357fe5b6020026020010151611a01565b8282815181106107ec57fe5b60209081029190910101526001016107ba565b5092915050565b61080e611768565b610816611781565b61057681611a2c565b600080600061082c611aaa565b159250610837611ac7565b9150610841611aeb565b9050909192565b6000610852611768565b61085a611829565b835161086581611b0f565b610874834211156101fc61054b565b61088760008760800151116101fe61054b565b60006108968760400151611b41565b905060006108a78860600151611b41565b90506108ca816001600160a01b0316836001600160a01b031614156101fd61054b565b6108d2614ce1565b885160808201526020890151819060018111156108eb57fe5b908160018111156108f857fe5b9052506001600160a01b03808416602083015282811660408084019190915260808b0151606084015260a08b01516101008401528951821660c08401528901511660e082015260008061094a83611b66565b9198509250905061098160008c60200151600181111561096657fe5b146109745789831115610979565b898210155b6101fb61054b565b6109998b60400151838c600001518d60200151611c5a565b6109b18b60600151828c604001518d60600151611d38565b6109d36109c18c60400151611938565b6109cc5760006109ce565b825b6119de565b5050505050506109e1611822565b949350505050565b6109f1611768565b6109f9611829565b610a0583518351611e12565b6060835167ffffffffffffffff81118015610a1f57600080fd5b50604051908082528060200260200182016040528015610a49578160200160208202803683370190505b5090506060845167ffffffffffffffff81118015610a6657600080fd5b50604051908082528060200260200182016040528015610a90578160200160208202803683370190505b5090506000805b8651811015610c09576000878281518110610aae57fe5b602002602001015190506000878381518110610ac657fe5b60200260200101519050610b11846001600160a01b0316836001600160a01b03161160006001600160a01b0316846001600160a01b031614610b09576066610b0c565b60685b61054b565b819350816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b409190615b63565b60206040518083038186803b158015610b5857600080fd5b505afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190615968565b858481518110610b9c57fe5b602002602001018181525050610bb181611e1f565b868481518110610bbd57fe5b602002602001018181525050610beb81868581518110610bd957fe5b6020026020010151101561021061054b565b610bff6001600160a01b0383168b83611ea6565b5050600101610a97565b506040517ff04f27070000000000000000000000000000000000000000000000000000000081526001600160a01b0388169063f04f270790610c55908990899088908a90600401615c85565b600060405180830381600087803b158015610c6f57600080fd5b505af1158015610c83573d6000803e3d6000fd5b5050505060005b8651811015610df4576000878281518110610ca157fe5b602002602001015190506000848381518110610cb957fe5b602002602001015190506000826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610cf19190615b63565b60206040518083038186803b158015610d0957600080fd5b505afa158015610d1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d419190615968565b9050610d528282101561020361054b565b60008282039050610d7b888681518110610d6857fe5b602002602001015182101561025a61054b565b610d858482611f11565b836001600160a01b03168c6001600160a01b03167f0d7d75e01ab95780d3cd1c8ec0dd6c2ce19e3a20427eec8bf53283b6fb8e95f08c8881518110610dc657fe5b602002602001015184604051610ddd929190615e4d565b60405180910390a350505050806001019050610c8a565b50505050610e00611822565b50505050565b610e0e611768565b610e16611829565b82610e2081611f33565b610e2c83518351611e12565b60005b8351811015610eca576000848281518110610e4657fe5b60200260200101519050610e7260006001600160a01b0316826001600160a01b0316141561013561054b565b838281518110610e7e57fe5b6020908102919091018101516000888152600a835260408082206001600160a01b0395861683529093529190912080546001600160a01b03191692909116919091179055600101610e2f565b506000610ed685611f64565b90506002816002811115610ee657fe5b1415610f3457610efc845160021461020c61054b565b610f2f8585600081518110610f0d57fe5b602002602001015186600181518110610f2257fe5b6020026020010151611f7e565b610f5c565b6001816002811115610f4257fe5b1415610f5257610f2f858561202a565b610f5c8585612082565b847ff5847d3f2197b16cdcd2098ec95d0905cd1abdaf415f07bb7cef2bba8ac5dec48585604051610f8e929190615bed565b60405180910390a25050610fa0611822565b505050565b610fad611768565b610fb5611829565b81610fbf81611f33565b6000610fca84611f64565b90506002816002811115610fda57fe5b141561102857610ff0835160021461020c61054b565b611023848460008151811061100157fe5b60200260200101518560018151811061101657fe5b60200260200101516120d7565b611050565b600181600281111561103657fe5b1415611046576110238484612145565b61105084846121ff565b60005b83518110156110b657600a6000868152602001908152602001600020600085838151811061107d57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b0319169055600101611053565b50837f7dcdc6d02ef40c7c1a7046a011b058bd7f988fa14e20a66344f9d4e60657d610846040516110e79190615bda565b60405180910390a25050610559611822565b60007f00000000000000000000000000000000000000000000000000000000000000008260405160200161112e929190615ac2565b604051602081830303815290604052805190602001209050919050565b610e00600185858561115c86612262565b61226e565b6001600160a01b031660009081526002602052604090205490565b6060611186611768565b61118e611829565b835161119981611b0f565b6111a8834211156101fc61054b565b6111b486518551611e12565b6111c08787878b6123f4565b91506000805b87518110156112925760008882815181106111dd57fe5b6020026020010151905060008583815181106111f557fe5b6020026020010151905061122188848151811061120e57fe5b60200260200101518213156101fb61054b565b600081131561126157885160208a015182916112409185918491611c5a565b61124983611938565b1561125b576112588582611945565b94505b50611288565b600081121561128857600081600003905061128683828c604001518d60600151611d38565b505b50506001016111c6565b5061129c816119de565b50506112a6611822565b9695505050505050565b60035461010090046001600160a01b031690565b60006112ce610526565b905090565b600080600080856112e381612683565b6000806112ef89611f64565b905060028160028111156112ff57fe5b14156113165761130f89896126a1565b9150611341565b600181600281111561132457fe5b14156113345761130f898961271b565b61133e8989612789565b91505b61134a826127a1565b9650611355826127b4565b9550611360826127ca565b6000998a52600a60209081526040808c206001600160a01b039b8c168d5290915290992054969995989796909616955050505050565b61139e611829565b610e00600085858561115c86612262565b7f000000000000000000000000000000000000000000000000000000000000000090565b6113db611768565b6113e3611829565b6113eb614d31565b60005b82518110156114e55782818151811061140357fe5b6020026020010151915060008260200151905061141f81612683565b604083015161143961143183836127d0565b61020961054b565b6000828152600a602090815260408083206001600160a01b03858116855292529091205461146c911633146101f661054b565b835160608501516000806114828487878661282c565b91509150846001600160a01b0316336001600160a01b0316877f6edcaf6241105b4c94c2efdbf3a6b12458eb3d07be3a0e81d24b13c44045fe7a85856040516114cc929190615e4d565b60405180910390a45050505050508060010190506113ee565b505061057e611822565b60006112ce61289b565b6000808261150681612683565b61150f84612938565b61151885611f64565b925092505b50915091565b60603330146115f6576000306001600160a01b0316600036604051611549929190615ada565b6000604051808303816000865af19150503d8060008114611586576040519150601f19603f3d011682016040523d82523d6000602084013e61158b565b606091505b50509050806000811461159a57fe5b60046000803e6000516001600160e01b0319167ffa61cc120000000000000000000000000000000000000000000000000000000081146115de573d6000803e3d6000fd5b50602060005260043d0380600460203e602081016000f35b6060611604858585896123f4565b9050602081510263fa61cc126020830352600482036024820181fd5b60608060008361162f81612683565b606061163a8661293e565b9095509050611648816129a0565b95979096509350505050565b61165c611768565b611664611829565b8261166e81611b0f565b6001600160a01b0384811660008181526004602090815260408083209488168084529490915290819020805460ff1916861515179055519091907f46961fdb4502b646d5095fba7600486a8ac05041d55cdf0f16ed677180b5cad8906116d5908690615d1b565b60405180910390a350610fa0611822565b60006116f28383612a4f565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b61177a6002600054141561019061054b565b6002600055565b60006117986000356001600160e01b0319166110f9565b905061057e6117a78233612a7d565b61019161054b565b6040516001600160a01b038216907f94b979b6831a51293e2641426f97747feed46f17779fed9cd18d1ecefcfe92ef90600090a2600380546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b6001600055565b61183c611834611aaa565b61019261054b565b565b600069ffffffffffffffffffff8216605084600281111561185b57fe5b901b17606085901b6bffffffffffffffffffffffff19161790505b9392505050565b600080600080600080600088606001519050336001600160a01b0316816001600160a01b0316146118cf57876118ba576118b5611781565b600197505b6118cf6118c78233612a4f565b6101f761054b565b885160208a015160408b01516080909b0151919b909a9992985090965090945092505050565b61190a8361190286611b41565b836000612b20565b50610e008482846000611d38565b61192b8261192586611b41565b83612b76565b610e008482856000611c5a565b6001600160a01b03161590565b60008282016116f2848210158361054b565b6119648385836000612b20565b50610e00828583612b76565b8015610e005761198b6001600160a01b038516848484612ba6565b826001600160a01b0316846001600160a01b03167f540a1a3f28340caec336c81d8d7b3df139ee5cdc1839a4f283d7ebb7eaae2d5c84846040516119d0929190615bc1565b60405180910390a350505050565b6119ed8134101561020461054b565b348190038015610559576105593382612bc7565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b8015611a4c57611a47611a3d611ac7565b421061019361054b565b611a61565b611a61611a57611aeb565b42106101a961054b565b6003805460ff19168215151790556040517f9e3a5e37224532dea67b89face185703738a228a6e8a23dee546960180d3be6490611a9f908390615d1b565b60405180910390a150565b6000611ab4611aeb565b4211806112ce57505060035460ff161590565b7f000000000000000000000000000000000000000000000000000000000000000090565b7f000000000000000000000000000000000000000000000000000000000000000090565b336001600160a01b0382161461057e57611b27611781565b611b318133612a4f565b61057e5761057e816101f7612c41565b6000611b4c82611938565b611b5e57611b5982610548565b6116f5565b6116f5610526565b600080600080611b798560800151612938565b90506000611b8a8660800151611f64565b90506002816002811115611b9a57fe5b1415611bb157611baa8683612c75565b9450611bdc565b6001816002811115611bbf57fe5b1415611bcf57611baa8683612d25565b611bd98683612db8565b94505b611bef8660000151876060015187612ff7565b809450819550505085604001516001600160a01b031686602001516001600160a01b031687608001517f2170c741c41531aec20e7c107c24eecfdd15e69c9bb0a8dd37b1840b9e0b207b8787604051611c49929190615e4d565b60405180910390a450509193909250565b82611c6457610e00565b611c6d84611938565b15611cee57611c7f811561020261054b565b611c8e8347101561020461054b565b611c96610526565b6001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611cd057600080fd5b505af1158015611ce4573d6000803e3d6000fd5b5050505050610e00565b6000611cf985610548565b90508115611d16576000611d108483876001612b20565b90940393505b8315611d3157611d316001600160a01b038216843087612ba6565b5050505050565b82611d4257610e00565b611d4b84611938565b15611ddb57611d5d811561020261054b565b611d65610526565b6001600160a01b0316632e1a7d4d846040518263ffffffff1660e01b8152600401611d909190615d3e565b600060405180830381600087803b158015611daa57600080fd5b505af1158015611dbe573d6000803e3d6000fd5b50611dd6925050506001600160a01b03831684612bc7565b610e00565b6000611de685610548565b90508115611dfe57611df9838286612b76565b611d31565b611d316001600160a01b0382168486611ea6565b610559818314606761054b565b600080611e2a6113af565b6001600160a01b031663d877845c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6257600080fd5b505afa158015611e76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9a9190615968565b90506118768382613025565b610fa08363a9059cbb60e01b8484604051602401611ec5929190615bc1565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b031990931692909217909152613072565b801561055957610559611f226113af565b6001600160a01b0384169083611ea6565b611f3c81612683565b61057e611f4882612938565b6001600160a01b0316336001600160a01b0316146101f561054b565b600061ffff605083901c166116f5600382106101f461054b565b611f9f816001600160a01b0316836001600160a01b0316141561020a61054b565b611fbe816001600160a01b0316836001600160a01b031610606661054b565b60008381526009602052604090208054611ffb906001600160a01b0316158015611ff3575060018201546001600160a01b0316155b61020b61054b565b80546001600160a01b039384166001600160a01b03199182161782556001909101805492909316911617905550565b6000828152600860205260408120905b8251811015610e0057600061206b84838151811061205457fe5b60200260200101518461311290919063ffffffff16565b90506120798161020a61054b565b5060010161203a565b6000828152600160205260408120905b8251811015610e005760006120c08483815181106120ac57fe5b602090810291909101015184906000613175565b90506120ce8161020a61054b565b50600101612092565b60008060006120e7868686613222565b9250925092506121116120f9846132e9565b80156121095750612109836132e9565b61020d61054b565b600095865260096020526040862080546001600160a01b031990811682556001909101805490911690559490945550505050565b6000828152600860205260408120905b8251811015610e0057600083828151811061216c57fe5b602002602001015190506121b8612109600760008881526020019081526020016000206000846001600160a01b03166001600160a01b03168152602001908152602001600020546132e9565b60008581526007602090815260408083206001600160a01b038516845290915281208190556121e7848361330b565b90506121f58161020961054b565b5050600101612155565b6000828152600160205260408120905b8251811015610e0057600083828151811061222657fe5b60200260200101519050600061223c8483613412565b905061224a612109826132e9565b6122548483613421565b50505080600101905061220f565b61226a614d5a565b5090565b612276611768565b8361228081612683565b8361228a81611b0f565b61229e836000015151846020015151611e12565b60606122ad84600001516134c3565b905060606122bb8883613552565b905060608060606122d08c8c8c8c8c896135e3565b92509250925060006122e18c611f64565b905060028160028111156122f157fe5b1415612359576123548c8760008151811061230857fe5b60200260200101518660008151811061231d57fe5b60200260200101518960018151811061233257fe5b60200260200101518860018151811061234757fe5b60200260200101516137a8565b612382565b600181600281111561236757fe5b1415612378576123548c87866137e7565b6123828c85613854565b6000808e600181111561239157fe5b1490508b6001600160a01b03168d7fe5ce249087ce04f05a957192435400fd97868dba0e6a4b4c049abf8af80dae78896123cb888661389d565b876040516123db93929190615c4c565b60405180910390a3505050505050505050611d31611822565b6060835167ffffffffffffffff8111801561240e57600080fd5b50604051908082528060200260200182016040528015612438578160200160208202803683370190505b509050612443614d84565b61244b614ce1565b60008060005b89518110156126765789818151811061246657fe5b6020026020010151945060008951866020015110801561248a575089518660400151105b905061249781606461054b565b60006124b98b8860200151815181106124ac57fe5b6020026020010151611b41565b905060006124d08c8960400151815181106124ac57fe5b90506124f3816001600160a01b0316836001600160a01b031614156101fd61054b565b60608801516125435761250b600085116101fe61054b565b60006125188b8484613945565b6001600160a01b0316876001600160a01b031614905061253a816101ff61054b565b50606088018590525b87516080880152868a600181111561255757fe5b9081600181111561256457fe5b9052506001600160a01b0380831660208901528181166040808a01919091526060808b0151908a015260808a01516101008a01528c51821660c08a01528c01511660e08801526000806125b689611b66565b919850925090506125c88c8585613967565b97506125fc6125d683613981565b8c8c60200151815181106125e657fe5b60200260200101516139b190919063ffffffff16565b8b8b602001518151811061260c57fe5b60200260200101818152505061264a61262482613981565b8c8c604001518151811061263457fe5b60200260200101516139e590919063ffffffff16565b8b8b604001518151811061265a57fe5b6020026020010181815250505050505050806001019050612451565b5050505050949350505050565b60008181526005602052604090205461057e9060ff166101f461054b565b60008060008060006126b287613a19565b945094509450945050836001600160a01b0316866001600160a01b031614156126e157829450505050506116f5565b816001600160a01b0316866001600160a01b031614156127065793506116f592505050565b6127116102096116fb565b5050505092915050565b60008281526007602090815260408083206001600160a01b03851684529091528120548161274882613a8f565b80612766575060008581526008602052604090206127669085613aa1565b9050806127815761277685612683565b6127816102096116fb565b509392505050565b60008281526001602052604081206109e18184613412565b6dffffffffffffffffffffffffffff1690565b60701c6dffffffffffffffffffffffffffff1690565b60e01c90565b6000806127dc84611f64565b905060028160028111156127ec57fe5b1415612804576127fc8484613ac2565b9150506116f5565b600181600281111561281257fe5b1415612822576127fc8484613b13565b6127fc8484613b2b565b600080600061283a86611f64565b9050600087600281111561284a57fe5b14156128665761285c86828787613b43565b9250925050612892565b600187600281111561287457fe5b14156128865761285c86828787613bbe565b61285c86828787613c3a565b94509492505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612908613c9d565b3060405160200161291d959493929190615df0565b60405160208183030381529060405280519060200120905090565b60601c90565b606080600061294c84611f64565b9050600281600281111561295c57fe5b14156129755761296b84613ca1565b925092505061299b565b600181600281111561298357fe5b14156129925761296b84613dd6565b61296b84613efd565b915091565b60606000825167ffffffffffffffff811180156129bc57600080fd5b506040519080825280602002602001820160405280156129e6578160200160208202803683370190505b5091506000905060005b825181101561151d576000848281518110612a0757fe5b60200260200101519050612a1a81613ff9565b848381518110612a2657fe5b602002602001018181525050612a4483612a3f836127ca565b614014565b9250506001016129f0565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b6003546040517f9be2a88400000000000000000000000000000000000000000000000000000000815260009161010090046001600160a01b031690639be2a88490612ad090869086903090600401615d47565b60206040518083038186803b158015612ae857600080fd5b505afa158015612afc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f29190615478565b600080612b2d8686611a01565b9050612b468380612b3e5750848210155b61020161054b565b612b50818561402b565b9150818103612b6c878783612b6487613981565b60000361403a565b5050949350505050565b6000612b828484611a01565b90506000612b908284611945565b9050611d31858583612ba187613981565b61403a565b610e00846323b872dd60e01b858585604051602401611ec593929190615b77565b612bd6814710156101a361054b565b6000826001600160a01b031682604051612bef90610548565b60006040518083038185875af1925050503d8060008114612c2c576040519150601f19603f3d011682016040523d82523d6000602084013e612c31565b606091505b50509050610fa0816101a461054b565b6001600160a01b0382166000908152600260205260409020805460018101909155610fa0612c6f8483614095565b8361054b565b600080600080612c92866080015187602001518860400151613222565b92509250925060008087604001516001600160a01b031688602001516001600160a01b03161015612cc7575083905082612ccd565b50829050835b612cd9888884846141bb565b60408b015160208c01519199509294509092506001600160a01b03918216911610612d0d57612d0881836142d1565b612d17565b612d1782826142d1565b909255509295945050505050565b600080612d3a8460800151856020015161271b565b90506000612d508560800151866040015161271b565b9050612d5e858584846141bb565b6080880180516000908152600760208181526040808420828e01516001600160a01b03908116865290835281852098909855935183529081528282209a830151909516815298909352919096209590955550929392505050565b60808201516000908152600160209081526040822090840151829182918290612de290839061430c565b90506000612dfd88604001518461430c90919063ffffffff16565b9050811580612e0a575080155b15612e2757612e1c8860800151612683565b612e276102096116fb565b60001991820191016000612e3a8461432b565b905060608167ffffffffffffffff81118015612e5557600080fd5b50604051908082528060200260200182016040528015612e7f578160200160208202803683370190505b50600060a08c018190529091505b82811015612eff576000612ea1878361432f565b9050612eac81613ff9565b838381518110612eb857fe5b602002602001018181525050612ed58c60a00151612a3f836127ca565b60a08d015281861415612eea57809850612ef6565b84821415612ef6578097505b50600101612e8d565b506040517f01ec954a0000000000000000000000000000000000000000000000000000000081526001600160a01b038a16906301ec954a90612f4b908d90859089908990600401615e5b565b602060405180830381600087803b158015612f6557600080fd5b505af1158015612f79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9d9190615968565b9750600080612fb58c600001518d606001518c612ff7565b9092509050612fc48983614345565b9850612fd08882614376565b9750612fdd87878b61438c565b612fe887868a61438c565b50505050505050505092915050565b6000808085600181111561300757fe5b141561301757508290508161301d565b50819050825b935093915050565b600082820261304984158061304257508385838161303f57fe5b04145b600361054b565b806130585760009150506116f5565b670de0b6b3a76400006000198201046001019150506116f5565b60006060836001600160a01b03168360405161308e9190615aea565b6000604051808303816000865af19150503d80600081146130cb576040519150601f19603f3d011682016040523d82523d6000602084013e6130d0565b606091505b509150915060008214156130e8573d6000803e3d6000fd5b610e0081516000148061310a57508180602001905181019061310a9190615478565b6101a261054b565b600061311e8383613aa1565b61316d57508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b038616908117909155855490825282860190935260409020919091556116f5565b5060006116f5565b6001600160a01b03821660009081526002840160205260408120548061320257505082546040805180820182526001600160a01b03858116808352602080840187815260008781526001808c018452878220965187546001600160a01b03191696169590951786559051948401949094559482018089559083526002880190945291902091909155611876565b600019016000908152600180860160205260408220018390559050611876565b600080600080600061323487876143a4565b91509150600061324483836143d5565b60008a81526009602090815260408083208484526002019091528120805460018201549197509293509061327783613a8f565b80613286575061328682613a8f565b806132a757506132968c87613ac2565b80156132a757506132a78c86613ac2565b9050806132c2576132b78c612683565b6132c26102096116fb565b6132cc8383614408565b98506132d8838361442d565b975050505050505093509350939050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6001600160a01b03811660009081526001830160205260408120548015613408578354600019808301919081019060009087908390811061334857fe5b60009182526020909120015487546001600160a01b039091169150819088908590811061337157fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b039485161790559183168152600189810190925260409020908401905586548790806133ba57fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03881682526001898101909152604082209190915594506116f59350505050565b60009150506116f5565b60006116f28383610209614444565b6001600160a01b0381166000908152600283016020526040812054801561340857835460001990810160008181526001878101602090815260408084209587018452808420865481546001600160a01b03199081166001600160a01b0392831617835588860180549387019390935588548216875260028d018086528488209a909a5588541690975584905593895593871682529390925281205590506116f5565b606080825167ffffffffffffffff811180156134de57600080fd5b50604051908082528060200260200182016040528015613508578160200160208202803683370190505b50905060005b83518110156107ff576135268482815181106124ac57fe5b82828151811061353257fe5b6001600160a01b039092166020928302919091019091015260010161350e565b60608060606135608561293e565b9150915061357082518551611e12565b613580600083511161020f61054b565b60005b82518110156135da576135d285828151811061359b57fe5b60200260200101516001600160a01b03168483815181106135b857fe5b60200260200101516001600160a01b03161461020861054b565b600101613583565b50949350505050565b60608060608060006135f4866129a0565b9150915060006136038b612938565b905060008c600181111561361357fe5b146136b657806001600160a01b03166374f3b0098c8c8c8787613634614481565b8f604001516040518863ffffffff1660e01b815260040161365b9796959493929190615d66565b600060405180830381600087803b15801561367557600080fd5b505af1158015613689573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136b19190810190615405565b61374f565b806001600160a01b031663d5c096c48c8c8c87876136d2614481565b8f604001516040518863ffffffff1660e01b81526004016136f99796959493929190615d66565b600060405180830381600087803b15801561371357600080fd5b505af1158015613727573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261374f9190810190615405565b80955081965050506137658751865186516144fb565b60008c600181111561377357fe5b1461378a576137858989898888614513565b613797565b6137978a8989888861465a565b955050505096509650969350505050565b60006137b485846143d5565b600087815260096020908152604080832084845260020190915290209091506137dd85846142d1565b9055505050505050565b60005b8251811015610e00578181815181106137ff57fe5b602002602001015160076000868152602001908152602001600020600085848151811061382857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001016137ea565b6000828152600160205260408120905b8251811015610e00576138958184838151811061387d57fe5b60200260200101518461438c9092919063ffffffff16565b600101613864565b6060825167ffffffffffffffff811180156138b757600080fd5b506040519080825280602002602001820160405280156138e1578160200160208202803683370190505b50905060005b83518110156107ff57826139115783818151811061390157fe5b6020026020010151600003613926565b83818151811061391d57fe5b60200260200101515b82828151811061393257fe5b60209081029190910101526001016138e7565b60008084600181111561395457fe5b1461395f57816109e1565b509092915050565b60008084600181111561397657fe5b146107ff57826109e1565b600061226a7f800000000000000000000000000000000000000000000000000000000000000083106101a561054b565b60008282016116f28284128015906139c95750848212155b806139de57506000841280156139de57508482125b600061054b565b60008183036116f28284128015906139fd5750848213155b80613a125750600084128015613a1257508482135b600161054b565b6000818152600960205260408120805460018201546001600160a01b0391821692849290911690829081613a4d86856143d5565b6000818152600284016020526040902080546001820154919950919250613a748282614408565b9650613a80828261442d565b94505050505091939590929450565b6000613a9a826132e9565b1592915050565b6001600160a01b031660009081526001919091016020526040902054151590565b600082815260096020526040812080546001600160a01b0384811691161480613afa575060018101546001600160a01b038481169116145b80156109e1575050506001600160a01b03161515919050565b60008281526008602052604081206109e18184613aa1565b60008281526001602052604081206109e181846147d0565b6000806002856002811115613b5457fe5b1415613b6a57613b658685856147f1565b613b94565b6001856002811115613b7857fe5b1415613b8957613b658685856147ff565b613b9486858561480d565b8215613bae57613bae6001600160a01b0385163385611ea6565b5050600081900394909350915050565b6000806002856002811115613bcf57fe5b1415613be557613be086858561481b565b613c0f565b6001856002811115613bf357fe5b1415613c0457613be0868585614829565b613c0f868585614837565b8215613c2a57613c2a6001600160a01b038516333086612ba6565b5090946000869003945092505050565b6000806002856002811115613c4b57fe5b1415613c6357613c5c868585614845565b9050613c90565b6001856002811115613c7157fe5b1415613c8257613c5c868585614855565b613c8d868585614865565b90505b6000915094509492505050565b4690565b606080600080600080613cb387613a19565b92975090955093509150506001600160a01b0384161580613cdb57506001600160a01b038216155b15613d04575050604080516000808252602082019081528183019092529450925061299b915050565b60408051600280825260608201835290916020830190803683370190505095508386600081518110613d3257fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508186600181518110613d6057fe5b6001600160a01b03929092166020928302919091018201526040805160028082526060820183529092909190830190803683370190505094508285600081518110613da757fe5b6020026020010181815250508085600181518110613dc157fe5b60200260200101818152505050505050915091565b60008181526008602052604090206060908190613df28161432b565b67ffffffffffffffff81118015613e0857600080fd5b50604051908082528060200260200182016040528015613e32578160200160208202803683370190505b509250825167ffffffffffffffff81118015613e4d57600080fd5b50604051908082528060200260200182016040528015613e77578160200160208202803683370190505b50915060005b8351811015613ef6576000613e928383614875565b905080858381518110613ea157fe5b6001600160a01b03928316602091820292909201810191909152600088815260078252604080822093851682529290915220548451859084908110613ee257fe5b602090810291909101015250600101613e7d565b5050915091565b60008181526001602052604090206060908190613f198161432b565b67ffffffffffffffff81118015613f2f57600080fd5b50604051908082528060200260200182016040528015613f59578160200160208202803683370190505b509250825167ffffffffffffffff81118015613f7457600080fd5b50604051908082528060200260200182016040528015613f9e578160200160208202803683370190505b50915060005b8351811015613ef657613fb782826148a2565b858381518110613fc357fe5b60200260200101858481518110613fd657fe5b60209081029190910101919091526001600160a01b039091169052600101613fa4565b6000614004826127b4565b61400d836127a1565b0192915050565b60008183101561402457816116f2565b5090919050565b600081831061402457816116f2565b6001600160a01b038085166000818152600b602090815260408083209488168084529490915290819020859055517f18e1ea4139e68413d7d08aa752e71568e36b2c5bf940893314c2c5b01eaa0c42906119d0908590615d3e565b6000806140a06148c6565b9050428110156140b45760009150506116f5565b60006140be6148d2565b9050806140d0576000925050506116f5565b6000816140db6149e3565b80516020918201206040516140f7939233918a91899101615dc4565b604051602081830303815290604052805190602001209050600061411a82614a32565b90506000806000614129614a4e565b9250925092506000600185858585604051600081526020016040526040516141549493929190615e1c565b6020604051602081039080840390855afa158015614176573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906141ac57508a6001600160a01b0316816001600160a01b0316145b9b9a5050505050505050505050565b6000806000806141ca86613ff9565b905060006141d786613ff9565b90506141ee6141e5886127ca565b612a3f886127ca565b60a08a01526040517f9d2c110c0000000000000000000000000000000000000000000000000000000081526001600160a01b03891690639d2c110c9061423c908c9086908690600401615e94565b602060405180830381600087803b15801561425657600080fd5b505af115801561426a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061428e9190615968565b92506000806142a68b600001518c6060015187612ff7565b90925090506142b58983614345565b96506142c18882614376565b9550505050509450945094915050565b6000806142e96142e0856127ca565b612a3f856127ca565b90506109e16142f7856127a1565b614300856127a1565b8363ffffffff16614a75565b6001600160a01b03166000908152600291909101602052604090205490565b5490565b6000908152600191820160205260409020015490565b60008061435b83614355866127a1565b90611945565b90506000614368856127b4565b9050436112a6838383614a83565b60008061435b83614386866127a1565b90614abc565b60009182526001928301602052604090912090910155565b600080826001600160a01b0316846001600160a01b0316106143c75782846143ca565b83835b915091509250929050565b600082826040516020016143ea929190615b06565b60405160208183030381529060405280519060200120905092915050565b60006116f2614416846127a1565b61441f846127a1565b614428866127ca565b614a83565b60006116f261443b846127b4565b61441f846127b4565b6001600160a01b038216600090815260028401602052604081205461446b8115158461054b565b614478856001830361432f565b95945050505050565b600061448b6113af565b6001600160a01b03166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b1580156144c357600080fd5b505afa1580156144d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ce9190615968565b610fa0828414801561450c57508183145b606761054b565b6060835167ffffffffffffffff8111801561452d57600080fd5b50604051908082528060200260200182016040528015614557578160200160208202803683370190505b50905060005b85515181101561465057600084828151811061457557fe5b602002602001015190506145a58760200151838151811061459257fe5b60200260200101518210156101f961054b565b6000876000015183815181106145b757fe5b602002602001015190506145d181838b8b60600151611d38565b60008584815181106145df57fe5b602002602001015190506145fb6145f583611b41565b82611f11565b61462a6146088483611945565b89868151811061461457fe5b602002602001015161437690919063ffffffff16565b85858151811061463657fe5b60200260200101818152505050505080600101905061455d565b5095945050505050565b60606000845167ffffffffffffffff8111801561467657600080fd5b506040519080825280602002602001820160405280156146a0578160200160208202803683370190505b50915060005b8651518110156147c65760008582815181106146be57fe5b602002602001015190506146ee886020015183815181106146db57fe5b60200260200101518211156101fa61054b565b60008860000151838151811061470057fe5b6020026020010151905061471a81838c8c60600151611c5a565b61472381611938565b15614735576147328483611945565b93505b600086848151811061474357fe5b602002602001015190506147596145f583611b41565b80831015614778576147738382038a868151811061461457fe5b6147a0565b6147a08184038a868151811061478a57fe5b602002602001015161434590919063ffffffff16565b8685815181106147ac57fe5b6020026020010181815250505050508060010190506146a6565b50614650816119de565b6001600160a01b031660009081526002919091016020526040902054151590565b610e008383614ad284614b0d565b610e008383614ad284614bb8565b610e008383614ad284614c13565b610e008383614c6284614b0d565b610e008383614c6284614bb8565b610e008383614c6284614c13565b60006109e18484614c8385614b0d565b60006109e18484614c8385614bb8565b60006109e18484614c8385614c13565b600082600001828154811061488657fe5b6000918252602090912001546001600160a01b03169392505050565b600090815260019182016020526040902080549101546001600160a01b0390911691565b60006112ce6000614c9d565b6000803560e01c8063b95cac28811461491a57638bdb39138114614942576352bbbe29811461496a5763945bcec981146149925763fa6e671d81146149ba57600092506149de565b7f3f7b71252bd19113ff48c19c6e004a9bcfcca320a0d74d58e85877cbd7dcae5892506149de565b7f8bbc57f66ea936902f50a71ce12b92c43f3c5340bb40c27c4e90ab84eeae335392506149de565b7fe192dcbc143b1e244ad73b813fd3c097b832ad260a157340b4e5e5beda067abe92506149de565b7f9bfc43a4d98313c6766986ffd7c916c7481566d9f224c6819af0a53388aced3a92506149de565b7fa3f865aa351e51cfeb40f5178d1564bb629fe9030b83caf6361d1baaf5b90b5a92505b505090565b60606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505082519293505050608010156105485760803603815290565b6000614a3c61289b565b8260405160200161112e929190615b2d565b6000806000614a5d6020614c9d565b9250614a696040614c9d565b91506108416060614c9d565b60e01b60709190911b010190565b6000838301614ab1858210801590614aa957506e01000000000000000000000000000082105b61020e61054b565b614478858585614a75565b6000614acc83831115600161054b565b50900390565b600080614ae283614386866127a1565b90506000614af384614355876127b4565b90506000614b00866127ca565b90506112a6838383614a83565b6000806000806000614b1e89613a19565b9450509350935093506000836001600160a01b0316896001600160a01b03161415614b69576000614b5384898b63ffffffff16565b9050614b5f8185614ca7565b9093509050614b8b565b6000614b7983898b63ffffffff16565b9050614b858184614ca7565b90925090505b614b9583836142d1565b8555614ba18383614cc3565b600190950194909455509192505050949350505050565b600080614bc5868661271b565b90506000614bd782858763ffffffff16565b60008881526007602090815260408083206001600160a01b038b16845290915290208190559050614c088183614ca7565b979650505050505050565b600084815260016020526040812081614c2c8287613412565b90506000614c3e82868863ffffffff16565b9050614c4b838883613175565b50614c568183614ca7565b98975050505050505050565b600080614c7283614355866127a1565b90506000614af384614386876127b4565b600080614c8f846127a1565b905043614478828583614a83565b3601607f19013590565b6000614cb2826127b4565b614cbb846127b4565b039392505050565b60006116f2614cd1846127b4565b614cda846127b4565b6000614a75565b60408051610120810190915280600081526000602082018190526040820181905260608083018290526080830182905260a0830182905260c0830182905260e08301919091526101009091015290565b604080516080810190915280600081526000602082018190526040820181905260609091015290565b60405180608001604052806060815260200160608152602001606081526020016000151581525090565b6040518060a0016040528060008019168152602001600081526020016000815260200160008152602001606081525090565b80356116f581615f5a565b600082601f830112614dd1578081fd5b8135614de4614ddf82615f04565b615edd565b818152915060208083019084810181840286018201871015614e0557600080fd5b60005b84811015614e2d578135614e1b81615f5a565b84529282019290820190600101614e08565b505050505092915050565b600082601f830112614e48578081fd5b8135614e56614ddf82615f04565b818152915060208083019084810160005b84811015614e2d578135870160a080601f19838c03011215614e8857600080fd5b614e9181615edd565b85830135815260408084013587830152606080850135828401526080915081850135818401525082840135925067ffffffffffffffff831115614ed357600080fd5b614ee18c8885870101614fc0565b90820152865250509282019290820190600101614e67565b600082601f830112614f09578081fd5b8135614f17614ddf82615f04565b818152915060208083019084810181840286018201871015614f3857600080fd5b60005b84811015614e2d57813584529282019290820190600101614f3b565b600082601f830112614f67578081fd5b8151614f75614ddf82615f04565b818152915060208083019084810181840286018201871015614f9657600080fd5b60005b84811015614e2d57815184529282019290820190600101614f99565b80356116f581615f6f565b600082601f830112614fd0578081fd5b813567ffffffffffffffff811115614fe6578182fd5b614ff9601f8201601f1916602001615edd565b915080825283602082850101111561501057600080fd5b8060208401602084013760009082016020015292915050565b80356116f581615f7d565b8035600281106116f557600080fd5b8035600481106116f557600080fd5b600060808284031215615063578081fd5b61506d6080615edd565b9050813567ffffffffffffffff8082111561508757600080fd5b61509385838601614dc1565b835260208401359150808211156150a957600080fd5b6150b585838601614ef9565b602084015260408401359150808211156150ce57600080fd5b506150db84828501614fc0565b6040830152506150ee8360608401614fb5565b606082015292915050565b60006080828403121561510a578081fd5b6151146080615edd565b9050813561512181615f5a565b8152602082013561513181615f6f565b6020820152604082013561514481615f5a565b604082015260608201356150ee81615f6f565b600060208284031215615168578081fd5b81356116f281615f5a565b60008060408385031215615185578081fd5b823561519081615f5a565b915060208301356151a081615f5a565b809150509250929050565b6000806000606084860312156151bf578081fd5b83356151ca81615f5a565b925060208401356151da81615f5a565b915060408401356151ea81615f6f565b809150509250925092565b60008060408385031215615207578182fd5b823561521281615f5a565b9150602083013567ffffffffffffffff81111561522d578182fd5b61523985828601614dc1565b9150509250929050565b60006020808385031215615255578182fd5b823567ffffffffffffffff81111561526b578283fd5b8301601f8101851361527b578283fd5b8035615289614ddf82615f04565b818152838101908385016080808502860187018a10156152a7578788fd5b8795505b848610156153105780828b0312156152c1578788fd5b6152ca81615edd565b6152d48b84615029565b8152878301358882015260406152ec8c828601614db6565b908201526060838101359082015284526001959095019492860192908101906152ab565b509098975050505050505050565b60006020808385031215615330578182fd5b823567ffffffffffffffff811115615346578283fd5b8301601f81018513615356578283fd5b8035615364614ddf82615f04565b8181528381019083850160a0808502860187018a1015615382578788fd5b8795505b848610156153105780828b03121561539c578788fd5b6153a581615edd565b6153af8b84615043565b81526153bd8b898501614db6565b818901526040838101359082015260606153d98c828601614db6565b9082015260806153eb8c858301614db6565b908201528452600195909501949286019290810190615386565b60008060408385031215615417578182fd5b825167ffffffffffffffff8082111561542e578384fd5b61543a86838701614f57565b9350602085015191508082111561544f578283fd5b5061523985828601614f57565b60006020828403121561546d578081fd5b81356116f281615f6f565b600060208284031215615489578081fd5b81516116f281615f6f565b6000602082840312156154a5578081fd5b5035919050565b600080600080608085870312156154c1578182fd5b8435935060208501356154d381615f5a565b925060408501356154e381615f5a565b9150606085013567ffffffffffffffff8111156154fe578182fd5b61550a87828801615052565b91505092959194509250565b60008060408385031215615528578182fd5b82359150602083013567ffffffffffffffff81111561522d578182fd5b600080600060608486031215615559578081fd5b8335925060208085013567ffffffffffffffff80821115615578578384fd5b61558488838901614dc1565b94506040870135915080821115615599578384fd5b508501601f810187136155aa578283fd5b80356155b8614ddf82615f04565b81815283810190838501858402850186018b10156155d4578687fd5b8694505b838510156155ff5780356155eb81615f5a565b8352600194909401939185019185016155d8565b5080955050505050509250925092565b60008060408385031215615621578182fd5b8235915060208301356151a081615f5a565b600060208284031215615644578081fd5b81356001600160e01b0319811681146116f2578182fd5b60008060008060808587031215615670578182fd5b843561567b81615f5a565b9350602085013567ffffffffffffffff80821115615697578384fd5b6156a388838901614dc1565b945060408701359150808211156156b8578384fd5b6156c488838901614ef9565b935060608701359150808211156156d9578283fd5b5061550a87828801614fc0565b6000602082840312156156f7578081fd5b81356116f281615f7d565b60008060008060e08587031215615717578182fd5b6157218686615034565b9350602085013567ffffffffffffffff8082111561573d578384fd5b61574988838901614e38565b9450604087013591508082111561575e578384fd5b5061576b87828801614dc1565b92505061577b86606087016150f9565b905092959194509250565b600080600080600080610120878903121561579f578384fd5b6157a98888615034565b955060208088013567ffffffffffffffff808211156157c6578687fd5b6157d28b838c01614e38565b975060408a01359150808211156157e7578687fd5b6157f38b838c01614dc1565b96506158028b60608c016150f9565b955060e08a0135915080821115615817578485fd5b508801601f81018a13615828578384fd5b8035615836614ddf82615f04565b81815283810190838501858402850186018e1015615852578788fd5b8794505b83851015615874578035835260019490940193918501918501615856565b50809650505050505061010087013590509295509295509295565b60008060008060e085870312156158a4578182fd5b843567ffffffffffffffff808211156158bb578384fd5b9086019060c082890312156158ce578384fd5b6158d860c0615edd565b823581526158e98960208501615034565b602082015260408301356158fc81615f5a565b604082015261590e8960608501614db6565b60608201526080830135608082015260a08301358281111561592e578586fd5b61593a8a828601614fc0565b60a08301525080965050505061595386602087016150f9565b939693955050505060a08201359160c0013590565b600060208284031215615979578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156159c55781516001600160a01b0316875295820195908201906001016159a0565b509495945050505050565b6000815180845260208085019450808401835b838110156159c5578151875295820195908201906001016159e3565b60008151808452615a17816020860160208601615f24565b601f01601f19169290920160200192915050565b6000610120825160028110615a3c57fe5b808552506020830151615a526020860182615980565b506040830151615a656040860182615980565b50606083015160608501526080830151608085015260a083015160a085015260c0830151615a9660c0860182615980565b5060e0830151615aa960e0860182615980565b506101008084015182828701526112a6838701826159ff565b9182526001600160e01b031916602082015260240190565b6000828483379101908152919050565b60008251615afc818460208701615f24565b9190910192915050565b6bffffffffffffffffffffffff19606093841b811682529190921b16601482015260280190565b7f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b038316815260408101615bb483615f50565b8260208301529392505050565b6001600160a01b03929092168252602082015260400190565b6000602082526116f2602083018461598d565b600060408252615c00604083018561598d565b828103602084810191909152845180835285820192820190845b81811015615c3f5784516001600160a01b031683529383019391830191600101615c1a565b5090979650505050505050565b600060608252615c5f606083018661598d565b8281036020840152615c7181866159d0565b905082810360408401526112a681856159d0565b600060808252615c98608083018761598d565b8281036020840152615caa81876159d0565b90508281036040840152615cbe81866159d0565b90508281036060840152614c0881856159ff565b600060608252615ce5606083018661598d565b8281036020840152615cf781866159d0565b915050826040830152949350505050565b6000602082526116f260208301846159d0565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60008882526001600160a01b03808916602084015280881660408401525060e06060830152615d9860e08301876159d0565b8560808401528460a084015282810360c0840152615db681856159ff565b9a9950505050505050505050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60208101615e4783615f50565b91905290565b918252602082015260400190565b600060808252615e6e6080830187615a2b565b8281036020840152615e8081876159d0565b604084019590955250506060015292915050565b600060608252615ea76060830186615a2b565b60208301949094525060400152919050565b938452602084019290925260408301526001600160a01b0316606082015260800190565b60405181810167ffffffffffffffff81118282101715615efc57600080fd5b604052919050565b600067ffffffffffffffff821115615f1a578081fd5b5060209081020190565b60005b83811015615f3f578181015183820152602001615f27565b83811115610e005750506000910152565b6003811061057e57fe5b6001600160a01b038116811461057e57600080fd5b801515811461057e57600080fd5b6003811061057e57600080fdfea2646970667358221220201e4f926e390fed8dd5318c58846af735c2bebc61b80693ae936a5fe76dcf1464736f6c6343000701003360c060405234801561001057600080fd5b50604051610be6380380610be683398101604081905261002f9161004d565b30608052600160005560601b6001600160601b03191660a05261007b565b60006020828403121561005e578081fd5b81516001600160a01b0381168114610074578182fd5b9392505050565b60805160a05160601c610b406100a66000398061041352806105495250806102a75250610b406000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063851c1bb311610076578063d877845c1161005b578063d877845c14610129578063e42abf3514610131578063fbfa77cf14610151576100a3565b8063851c1bb314610101578063aaabadc514610114576100a3565b806338e9922e146100a857806355c67628146100bd5780636b6b9f69146100db5780636daefab6146100ee575b600080fd5b6100bb6100b636600461099c565b610159565b005b6100c56101b8565b6040516100d29190610aa6565b60405180910390f35b6100bb6100e936600461099c565b6101be565b6100bb6100fc3660046107d1565b610211565b6100c561010f366004610924565b6102a3565b61011c6102f5565b6040516100d29190610a35565b6100c5610304565b61014461013f366004610852565b61030a565b6040516100d29190610a62565b61011c610411565b610161610435565b6101786706f05b59d3b2000082111561025861047e565b60018190556040517fa9ba3ffe0b6c366b81232caab38605a0699ad5398d6cce76f91ee809e322dafc906101ad908390610aa6565b60405180910390a150565b60015490565b6101c6610435565b6101dc662386f26fc1000082111561025961047e565b60028190556040517f5a0b7386237e7f07fa741efc64e59c9387d2cccafec760efed4d53387f20e19a906101ad908390610aa6565b610219610490565b610221610435565b61022b84836104a9565b60005b8481101561029357600086868381811061024457fe5b90506020020160208101906102599190610980565b9050600085858481811061026957fe5b6020029190910135915061028990506001600160a01b03831685836104b6565b505060010161022e565b5061029c61053e565b5050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000826040516020016102d89291906109cc565b604051602081830303815290604052805190602001209050919050565b60006102ff610545565b905090565b60025490565b6060815167ffffffffffffffff8111801561032457600080fd5b5060405190808252806020026020018201604052801561034e578160200160208202803683370190505b50905060005b825181101561040b5782818151811061036957fe5b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161039c9190610a35565b60206040518083038186803b1580156103b457600080fd5b505afa1580156103c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ec91906109b4565b8282815181106103f857fe5b6020908102919091010152600101610354565b50919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006104646000357fffffffff00000000000000000000000000000000000000000000000000000000166102a3565b905061047b61047382336105d8565b61019161047e565b50565b8161048c5761048c8161066a565b5050565b6104a26002600054141561019061047e565b6002600055565b61048c818314606761047e565b6105398363a9059cbb60e01b84846040516024016104d5929190610a49565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526106d7565b505050565b6001600055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663aaabadc56040518163ffffffff1660e01b815260040160206040518083038186803b1580156105a057600080fd5b505afa1580156105b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102ff9190610964565b60006105e2610545565b6001600160a01b0316639be2a8848484306040518463ffffffff1660e01b815260040161061193929190610aaf565b60206040518083038186803b15801561062957600080fd5b505afa15801561063d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066191906108fd565b90505b92915050565b7f08c379a0000000000000000000000000000000000000000000000000000000006000908152602060045260076024526642414c23000030600a808404818106603090810160081b95839006959095019082900491820690940160101b939093010160c81b604452606490fd5b60006060836001600160a01b0316836040516106f391906109fc565b6000604051808303816000865af19150503d8060008114610730576040519150601f19603f3d011682016040523d82523d6000602084013e610735565b606091505b5091509150600082141561074d573d6000803e3d6000fd5b61077781516000148061076f57508180602001905181019061076f91906108fd565b6101a261047e565b50505050565b60008083601f84011261078e578182fd5b50813567ffffffffffffffff8111156107a5578182fd5b60208301915083602080830285010111156107bf57600080fd5b9250929050565b803561066481610af5565b6000806000806000606086880312156107e8578081fd5b853567ffffffffffffffff808211156107ff578283fd5b61080b89838a0161077d565b90975095506020880135915080821115610823578283fd5b506108308882890161077d565b909450925050604086013561084481610af5565b809150509295509295909350565b60006020808385031215610864578182fd5b823567ffffffffffffffff8082111561087b578384fd5b818501915085601f83011261088e578384fd5b81358181111561089c578485fd5b83810291506108ac848301610ace565b8181528481019084860184860187018a10156108c6578788fd5b8795505b838610156108f0576108dc8a826107c6565b8352600195909501949186019186016108ca565b5098975050505050505050565b60006020828403121561090e578081fd5b8151801515811461091d578182fd5b9392505050565b600060208284031215610935578081fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461091d578182fd5b600060208284031215610975578081fd5b815161091d81610af5565b600060208284031215610991578081fd5b813561091d81610af5565b6000602082840312156109ad578081fd5b5035919050565b6000602082840312156109c5578081fd5b5051919050565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260240190565b60008251815b81811015610a1c5760208186018101518583015201610a02565b81811115610a2a5782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b81811015610a9a57835183529284019291840191600101610a7e565b50909695505050505050565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b60405181810167ffffffffffffffff81118282101715610aed57600080fd5b604052919050565b6001600160a01b038116811461047b57600080fdfea2646970667358221220be72bdf8e7a3c38606c5f954fbe2d77798347aaa1cfb76fe77ec2f6c245d24bc64736f6c6343000701003300000000000000000000000067af5d428d38c5176a286a2371df691cdd914fb800000000000000000000000080dd2b80fbcfb06505a301d732322e987380ecd6000000000000000000000000000000000000000000000000000000000076a7000000000000000000000000000000000000000000000000000000000000278d00

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000067af5d428d38c5176a286a2371df691cdd914fb800000000000000000000000080dd2b80fbcfb06505a301d732322e987380ecd6000000000000000000000000000000000000000000000000000000000076a7000000000000000000000000000000000000000000000000000000000000278d00

-----Decoded View---------------
Arg [0] : authorizer (address): 0x67af5d428d38c5176a286a2371df691cdd914fb8
Arg [1] : weth (address): 0x80dd2b80fbcfb06505a301d732322e987380ecd6
Arg [2] : pauseWindowDuration (uint256): 7776000
Arg [3] : bufferPeriodDuration (uint256): 2592000

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000067af5d428d38c5176a286a2371df691cdd914fb8
Arg [1] : 00000000000000000000000080dd2b80fbcfb06505a301d732322e987380ecd6
Arg [2] : 000000000000000000000000000000000000000000000000000000000076a700
Arg [3] : 0000000000000000000000000000000000000000000000000000000000278d00


Deployed ByteCode Sourcemap

3244:648:30:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6374:61:21;6405:7;:5;:7::i;:::-;-1:-1:-1;;;;;6383:30:21;:10;-1:-1:-1;;;;;6383:30:21;;9022:3:2;6374:8:21;:61::i;:::-;3244:648:30;;;;;3765:140:31;;;;;;;;;;-1:-1:-1;3765:140:31;;;;;:::i;:::-;;:::i;2550:771:25:-;;;;;;;;;;-1:-1:-1;2550:771:25;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2521:2571:29;;;;;;:::i;:::-;;:::i;2170:345::-;;;;;;;;;;-1:-1:-1;2170:345:29;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;3634:111:30:-;;;;;;;;;;-1:-1:-1;3634:111:30;;;;;:::i;:::-;;:::i;3154:363:8:-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;2389:2144:28:-;;;;;;:::i;:::-;;:::i;1451:2156:23:-;;;;;;;;;;-1:-1:-1;1451:2156:23;;;;;:::i;:::-;;:::i;1113:1188:26:-;;;;;;;;;;-1:-1:-1;1113:1188:26;;;;;:::i;:::-;;:::i;2307:1095::-;;;;;;;;;;-1:-1:-1;2307:1095:26;;;;;:::i;:::-;;:::i;2487:430:1:-;;;;;;;;;;-1:-1:-1;2487:430:1;;;;;:::i;:::-;;:::i;2309:384:24:-;;;;;;;;;;-1:-1:-1;2309:384:24;;;;;:::i;:::-;;:::i;1873:117:7:-;;;;;;;;;;-1:-1:-1;1873:117:7;;;;;:::i;:::-;;:::i;4539:1825:28:-;;;;;;:::i;:::-;;:::i;4067:105:31:-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;3804:86:30:-;;;;;;;;;;;;;:::i;3857:984:26:-;;;;;;;;;;-1:-1:-1;3857:984:26;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;:::i;1741:562:24:-;;;;;;:::i;:::-;;:::i;1462:135:22:-;;;;;;;;;;;;;:::i;1564:1096:20:-;;;;;;;;;;-1:-1:-1;1564:1096:20;;;;;:::i;:::-;;:::i;1752:115:7:-;;;;;;;;;;;;;:::i;3327:246:25:-;;;;;;;;;;-1:-1:-1;3327:246:25;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;19634:5730:28:-;;;;;;;;;;-1:-1:-1;19634:5730:28;;;;;:::i;:::-;;:::i;3408:443:26:-;;;;;;;;;;-1:-1:-1;3408:443:26;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;4178:301:31:-;;;;;;;;;;-1:-1:-1;4178:301:31;;;;;:::i;:::-;;:::i;4485:155::-;;;;;;;;;;-1:-1:-1;4485:155:31;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1420:76:0:-;1484:5;1420:76;;:::o;866:101:2:-;935:9;930:34;;946:18;954:9;946:7;:18::i;:::-;866:101;;:::o;3765:140:31:-;2561:20:17;:18;:20::i;:::-;2156:21:1::1;:19;:21::i;:::-;3869:29:31::2;3884:13;3869:14;:29::i;:::-;2602:19:17::0;:17;:19::i;:::-;3765:140:31;:::o;2550:771:25:-;2701:7;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;2902:14:25::2;2919:61;2929:10;2941:14;2964;;2919:9;:61::i;:::-;3001:25;::::0;;;:17:::2;:25;::::0;;;;;2902:78;;-1:-1:-1;2991:60:25::2;::::0;3001:25:::2;;3000:26;7978:3:2;2991:8:25;:60::i;:::-;3108:25;::::0;;;:17:::2;:25;::::0;;;;;;:32;;-1:-1:-1;;3108:32:25::2;3136:4;3108:32:::0;;::::2;::::0;;;3151:14:::2;:19:::0;;;;::::2;::::0;;3241:50;3264:10:::2;::::0;3126:6;;3241:50:::2;::::0;::::2;::::0;3276:14;;3241:50:::2;:::i;:::-;;;;;;;;3308:6:::0;-1:-1:-1;2602:19:17;:17;:19::i;:::-;2550:771:25;;;:::o;2521:2571:29:-;2561:20:17;:18;:20::i;:::-;2735:18:29::1;2844:27:::0;2889:21:::1;2934:9:::0;2929:2078:::1;2953:3;:10;2949:1;:14;2929:2078;;;2984:22;3020:12:::0;3046:14:::1;3074::::0;3102:25:::1;3328:100;3368:3;3372:1;3368:6;;;;;;;;;;;;;;3392:22;3328;:100::i;:::-;3261:167:::0;-1:-1:-1;3261:167:29;;-1:-1:-1;3261:167:29;;-1:-1:-1;3261:167:29;-1:-1:-1;3261:167:29;-1:-1:-1;3261:167:29;-1:-1:-1;3455:35:29::1;3447:4;:43;;;;;;;;;3443:1554;;;3608:62;3637:5;3644:6;3652:9;3663:6;3608:28;:62::i;:::-;3443:1554;;;3939:16;3934:127;;3979:18;:16;:18::i;:::-;4038:4;4019:23;;3934:127;4091:34;4083:4;:42;;;;;;;;;4079:904;;;4149:59;4175:5;4182:6;4190:9;4201:6;4149:25;:59::i;:::-;4320:13;4327:5;4320:6;:13::i;:::-;4316:103;;;4374:22;:10:::0;4389:6;4374:14:::1;:22::i;:::-;4361:35;;4079:904;;;4517:56;4527:13;4534:5;4527:6;:13::i;:::-;4526:14;9083:3:2;4517:8:29;:56::i;:::-;4595:12;4610:16;4620:5;4610:9;:16::i;:::-;4595:31:::0;-1:-1:-1;4661:35:29::1;4653:4;:43;;;;;;;;;4649:316;;;4724:58;4749:5;4756:6;4764:9;4775:6;4724:24;:58::i;:::-;4649:316;;;4882:60;4909:5;4916:6;4924:9;4935:6;4882:26;:60::i;:::-;4079:904;;-1:-1:-1::0;;2965:3:29::1;::::0;;::::1;::::0;-1:-1:-1;2929:2078:29::1;::::0;-1:-1:-1;;2929:2078:29::1;;;5054:31;5074:10;5054:19;:31::i;:::-;2591:1:17;;;2602:19:::0;:17;:19::i;2170:345:29:-;2300:25;2366:6;:13;2352:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2352:28:29;;2341:39;;2395:9;2390:119;2414:6;:13;2410:1;:17;2390:119;;;2462:36;2482:4;2488:6;2495:1;2488:9;;;;;;;;;;;;;;2462:19;:36::i;:::-;2448:8;2457:1;2448:11;;;;;;;;;;;;;;;;;:50;2429:3;;2390:119;;;;2170:345;;;;:::o;3634:111:30:-;2561:20:17;:18;:20::i;:::-;2156:21:1::1;:19;:21::i;:::-;3720:18:30::2;3731:6;3720:10;:18::i;3154:363:8:-:0;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;2389:2144:28:-;2681:24;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;2650:12:28::0;;3418:22:31::2;2650:12:28::0;3418:16:31::2;:22::i;:::-;2873:59:28::3;2901:8;2882:15;:27;;8414:3:2;2873:8:28;:59::i;:::-;3100:68;3129:1;3109:10;:17;;;:21;8540:3:2;3100:8:28;:68::i;:::-;3179:14;3196:38;3215:10;:18;;;3196;:38::i;:::-;3179:55;;3244:15;3262:39;3281:10;:19;;;3262:18;:39::i;:::-;3244:57;;3311:60;3331:8;-1:-1:-1::0;;;;;3320:19:28::3;:7;-1:-1:-1::0;;;;;3320:19:28::3;;;8474:3:2;3311:8:28;:60::i;:::-;3475:47;;:::i;:::-;3553:17:::0;;3532:18:::3;::::0;::::3;:38:::0;3599:15:::3;::::0;::::3;::::0;3532:11;;3580:34:::3;::::0;::::3;;;;;;;;;;;;;;;;::::0;;-1:-1:-1;;;;;;3624:29:28;;::::3;:19;::::0;::::3;:29:::0;3663:31;;::::3;:20;::::0;;::::3;:31:::0;;;;3725:17:::3;::::0;::::3;::::0;3704:18:::3;::::0;::::3;:38:::0;3775:19:::3;::::0;::::3;::::0;3752:20:::3;::::0;::::3;:42:::0;3823:12;;3804:31;::::3;:16;::::0;::::3;:31:::0;3862:15;::::3;::::0;3845:32:::3;:14;::::0;::::3;:32:::0;-1:-1:-1;;4044:26:28::3;3624:11:::0;4044:13:::3;:26::i;:::-;4002:68:::0;;-1:-1:-1;4002:68:28;-1:-1:-1;4002:68:28;-1:-1:-1;4080:106:28::3;4108:17;4089:10;:15;;;:36;;;;;;;;;:77;;4161:5;4149:8;:17;;4089:77;;;4141:5;4128:9;:18;;4089:77;8363:3:2;4080:8:28;:106::i;:::-;4197:84;4211:10;:18;;;4231:8;4241:5;:12;;;4255:5;:25;;;4197:13;:84::i;:::-;4291;4302:10;:19;;;4323:9;4334:5;:15;;;4351:5;:23;;;4291:10;:84::i;:::-;4464:62;4484:26;4491:10;:18;;;4484:6;:26::i;:::-;:41;;4524:1;4484:41;;;4513:8;4484:41;4464:19;:62::i;:::-;3450:1:31;;;;;2998::8::2;2602:19:17::0;:17;:19::i;:::-;2389:2144:28;;;;;;:::o;1451:2156:23:-;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;1667:66:23::2;1703:6;:13;1718:7;:14;1667:35;:66::i;:::-;1744:27;1788:6;:13;1774:28;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;1774:28:23::2;;1744:58;;1812:32;1861:6;:13;1847:28;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;1847:28:23::2;;1812:63;;1983:20;2031:9:::0;2026:565:::2;2050:6;:13;2046:1;:17;2026:565;;;2084:12;2099:6;2106:1;2099:9;;;;;;;;;;;;;;2084:24;;2122:14;2139:7;2147:1;2139:10;;;;;;;;;;;;;;2122:27;;2164:96;2181:13;-1:-1:-1::0;;;;;2173:21:23::2;:5;-1:-1:-1::0;;;;;2173:21:23::2;;2212:1;-1:-1:-1::0;;;;;2196:18:23::2;:5;-1:-1:-1::0;;;;;2196:18:23::2;;:63;;4943:3:2;2196:63:23;;;5050:3:2;2196:63:23;2164:8;:96::i;:::-;2290:5;2274:21;;2331:5;-1:-1:-1::0;;;;;2331:15:23::2;;2355:4;2331:30;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2310:15;2326:1;2310:18;;;;;;;;;;;;;:51;;;::::0;::::2;2391:36;2420:6;2391:28;:36::i;:::-;2375:10;2386:1;2375:13;;;;;;;;;;;;;:52;;;::::0;::::2;2442:78;2473:6;2451:15;2467:1;2451:18;;;;;;;;;;;;;;:28;;9613:3:2;2442:8:23;:78::i;:::-;2534:46;-1:-1:-1::0;;;;;2534:18:23;::::2;2561:9:::0;2573:6;2534:18:::2;:46::i;:::-;-1:-1:-1::0;;2065:3:23::2;;2026:565;;;-1:-1:-1::0;2601:65:23::2;::::0;;;;-1:-1:-1;;;;;2601:26:23;::::2;::::0;::::2;::::0;:65:::2;::::0;2628:6;;2636:7;;2645:10;;2657:8;;2601:65:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;2682:9;2677:924;2701:6;:13;2697:1;:17;2677:924;;;2735:12;2750:6;2757:1;2750:9;;;;;;;;;;;;;;2735:24;;2773:22;2798:15;2814:1;2798:18;;;;;;;;;;;;;;2773:43;;3049:23;3075:5;-1:-1:-1::0;;;;;3075:15:23::2;;3099:4;3075:30;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3049:56;;3119:77;3147:14;3128:15;:33;;8865:3:2;3119:8:23;:77::i;:::-;3298:25;3344:14;3326:15;:32;3298:60;;3372:87;3402:10;3413:1;3402:13;;;;;;;;;;;;;;3381:17;:34;;9836:3:2;3372:8:23;:87::i;:::-;3474:39;3488:5;3495:17;3474:13;:39::i;:::-;3553:5;-1:-1:-1::0;;;;;3532:58:23::2;3542:9;-1:-1:-1::0;;;;;3532:58:23::2;;3560:7;3568:1;3560:10;;;;;;;;;;;;;;3572:17;3532:58;;;;;;;:::i;:::-;;;;;;;;2677:924;;;;2716:3;;;;;2677:924;;;;2998:1:8;;;2602:19:17::0;:17;:19::i;:::-;1451:2156:23;;;;:::o;1113:1188:26:-;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;1293:6:26::2;1954:27:25;1974:6;1954:19;:27::i;:::-;1311:72:26::3;1347:6;:13;1362;:20;1311:35;:72::i;:::-;1463:9;1458:224;1482:6;:13;1478:1;:17;1458:224;;;1516:12;1531:6;1538:1;1531:9;;;;;;;;;;;;;;1516:24;;1554:50;1579:1;-1:-1:-1::0;;;;;1563:18:26::3;:5;-1:-1:-1::0;;;;;1563:18:26::3;;;6154:3:2;1554:8:26;:50::i;:::-;1655:13;1669:1;1655:16;;;;;;;;;::::0;;::::3;::::0;;;;;;;1619:26:::3;::::0;;;:18:::3;:26:::0;;;;;;-1:-1:-1;;;;;1619:33:26;;::::3;::::0;;;;;;;;;:52;;-1:-1:-1;;;;;;1619:52:26::3;::::0;;;::::3;::::0;;;::::3;::::0;;-1:-1:-1;1497:3:26::3;1458:224;;;;1692:33;1728:30;1751:6;1728:22;:30::i;:::-;1692:66:::0;-1:-1:-1;1790:28:26::3;1772:14;:46;;;;;;;;;1768:464;;;1834:60;1843:6;:13;1860:1;1843:18;9373:3:2;1834:8:26;:60::i;:::-;1908:57;1936:6;1944;1951:1;1944:9;;;;;;;;;;;;;;1955:6;1962:1;1955:9;;;;;;;;;;;;;;1908:27;:57::i;:::-;1768:464;;;2004:36;1986:14;:54;;;;;;;;;1982:250;;;2056:50;2091:6;2099;2056:34;:50::i;1982:250::-;2179:42;2206:6;2214;2179:26;:42::i;:::-;2264:6;2247:47;2272:6;2280:13;2247:47;;;;;;;:::i;:::-;;;;;;;;1991:1:25;2998::8::2;2602:19:17::0;:17;:19::i;:::-;1113:1188:26;;;:::o;2307:1095::-;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;2467:6:26::2;1954:27:25;1974:6;1954:19;:27::i;:::-;2489:33:26::3;2525:30;2548:6;2525:22;:30::i;:::-;2489:66:::0;-1:-1:-1;2587:28:26::3;2569:14;:46;;;;;;;;;2565:470;;;2631:60;2640:6;:13;2657:1;2640:18;9373:3:2;2631:8:26;:60::i;:::-;2705:59;2735:6;2743;2750:1;2743:9;;;;;;;;;;;;;;2754:6;2761:1;2754:9;;;;;;;;;;;;;;2705:29;:59::i;:::-;2565:470;;;2803:36;2785:14;:54;;;;;;;;;2781:254;;;2855:52;2892:6;2900;2855:36;:52::i;2781:254::-;2980:44;3009:6;3017;2980:28;:44::i;:::-;3238:9;3233:113;3257:6;:13;3253:1;:17;3233:113;;;3298:18;:26;3317:6;3298:26;;;;;;;;;;;:37;3325:6;3332:1;3325:9;;;;;;;;;::::0;;::::3;::::0;;;;;;;-1:-1:-1;;;;;3298:37:26::3;::::0;;;::::3;::::0;;;;;;-1:-1:-1;3298:37:26;3291:44;;-1:-1:-1;;;;;;3291:44:26::3;::::0;;;3272:3:::3;3233:113;;;;3380:6;3361:34;3388:6;3361:34;;;;;;:::i;:::-;;;;;;;;1991:1:25;2998::8::2;2602:19:17::0;:17;:19::i;2487:430:1:-;2555:7;2876:22;2900:8;2859:50;;;;;;;;;:::i;:::-;;;;;;;;;;;;;2849:61;;;;;;2842:68;;2487:430;;;:::o;2309:384:24:-;2589:97;2601:26;2629:6;2637;2645:9;2656:29;2677:7;2656:20;:29::i;:::-;2589:11;:97::i;1873:117:7:-;-1:-1:-1;;;;;1967:16:7;1941:7;1967:16;;;:10;:16;;;;;;;1873:117::o;4539:1825:28:-;4900:27;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;4869:12:28::0;;3418:22:31::2;4869:12:28::0;3418:16:31::2;:22::i;:::-;5095:59:28::3;5123:8;5104:15;:27;;8414:3:2;5095:8:28;:59::i;:::-;5165:65;5201:6;:13;5216:6;:13;5165:35;:65::i;:::-;5360:42;5375:5;5382:6;5390:5;5397:4;5360:14;:42::i;:::-;5346:56;;5568:18;5605:9:::0;5600:670:::3;5624:6;:13;5620:1;:17;5600:670;;;5658:12;5673:6;5680:1;5673:9;;;;;;;;;;;;;;5658:24;;5696:12;5711:11;5723:1;5711:14;;;;;;;;;;;;;;5696:29;;5739:47;5757:6;5764:1;5757:9;;;;;;;;;;;;;;5748:5;:18;;8363:3:2;5739:8:28;:47::i;:::-;5813:1;5805:5;:9;5801:459;;;5918:12:::0;;5932:25:::3;::::0;::::3;::::0;5862:5;;5886:72:::3;::::0;5900:5;;5862;;5886:13:::3;:72::i;:::-;5981:13;5988:5;5981:6;:13::i;:::-;5977:98;;;6031:25;:10:::0;6046:9;6031:14:::3;:25::i;:::-;6018:38;;5977:98;5801:459;;;;6107:1;6099:5;:9;6095:165;;;6128:14;6154:5;6153:6;;6128:32;;6178:67;6189:5;6196:6;6204:5;:15;;;6221:5;:23;;;6178:10;:67::i;:::-;6095:165;;-1:-1:-1::0;;5639:3:28::3;;5600:670;;;;6326:31;6346:10;6326:19;:31::i;:::-;3450:1:31;2998::8::2;2602:19:17::0;:17;:19::i;:::-;4539:1825:28;;;;;;;;:::o;4067:105:31:-;4154:11;;;;;-1:-1:-1;;;;;4154:11:31;;4067:105::o;3804:86:30:-;3852:5;3876:7;:5;:7::i;:::-;3869:14;;3804:86;:::o;3857:984:26:-;4025:12;4051:15;4080:23;4117:20;3987:6;1732:29:25;1754:6;1732:21;:29::i;:::-;4162:15:26::1;4187:33:::0;4223:30:::1;4246:6;4223:22;:30::i;:::-;4187:66:::0;-1:-1:-1;4286:28:26::1;4268:14;:46;;;;;;;;;4264:391;;;4340:38;4364:6;4372:5;4340:23;:38::i;:::-;4330:48;;4264:391;;;4417:36;4399:14;:54;;;;;;;;;4395:260;;;4479:45;4510:6;4518:5;4479:30;:45::i;4395:260::-;4607:37;4630:6;4638:5;4607:22;:37::i;:::-;4597:47;;4395:260;4672:14;:7;:12;:14::i;:::-;4665:21;;4706:17;:7;:15;:17::i;:::-;4696:27;;4751:25;:7;:23;:25::i;:::-;4801:26;::::0;;;:18:::1;:26;::::0;;;;;;;-1:-1:-1;;;;;4801:33:26;;::::1;::::0;;;;;;;;;3857:984;;;;4733:43;4801:33;;;::::1;::::0;-1:-1:-1;;;;;3857:984:26:o;1741:562:24:-;2970:18:8;:16;:18::i;:::-;2190:106:24::1;2202:26;2230:6;2238;2254:9;2266:29;2287:7;2266:20;:29::i;1462:135:22:-:0;1568:22;1462:135;:::o;1564:1096:20:-;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;1839:23:20::2;;:::i;:::-;1878:9;1873:781;1897:3;:10;1893:1;:14;1873:781;;;2032:3;2036:1;2032:6;;;;;;;;;;;;;;2027:11;;2053:14;2070:2;:9;;;2053:26;;2093:29;2115:6;2093:21;:29::i;:::-;2152:8;::::0;::::2;::::0;2174:72:::2;2183:33;2202:6:::0;2152:8;2183:18:::2;:33::i;:::-;9194:3:2;2174:8:20;:72::i;:::-;2269:26;::::0;;;:18:::2;:26;::::0;;;;;;;-1:-1:-1;;;;;2269:33:20;;::::2;::::0;;;;;;;;2260:90:::2;::::0;2269:33:::2;2306:10;2269:47;8093:3:2;2260:8:20;:90::i;:::-;2390:7:::0;;2428:9:::2;::::0;::::2;::::0;2365:22:::2;::::0;2493:60:::2;2390:7:::0;2531:6;2539:5;2428:9;2493:31:::2;:60::i;:::-;2451:102;;;;2612:5;-1:-1:-1::0;;;;;2573:70:20::2;2600:10;-1:-1:-1::0;;;;;2573:70:20::2;2592:6;2573:70;2619:9;2630:12;2573:70;;;;;;;:::i;:::-;;;;;;;;1873:781;;;;;;1909:3;;;;;1873:781;;;;2998:1:8;2602:19:17::0;:17;:19::i;1752:115:7:-;1814:7;1840:20;:18;:20::i;3327:246:25:-;3459:7;3468:18;3434:6;1732:29;1754:6;1732:21;:29::i;:::-;3510:23:::1;3526:6;3510:15;:23::i;:::-;3535:30;3558:6;3535:22;:30::i;:::-;3502:64;;;;1771:1;3327:246:::0;;;;:::o;19634:5730:28:-;19821:15;20944:10;20966:4;20944:27;20940:4418;;21240:12;21266:4;-1:-1:-1;;;;;21258:18:28;21277:8;;21258:28;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21239:47;;;21502:7;21535:1;21530:2283;;;;23973:9;21530:2283;22006:4;22003:1;22000;21985:26;22059:1;22053:8;-1:-1:-1;;;;;;22049:81:28;22291:66;22281:77;;22275:2;;22414:16;22411:1;22408;22393:38;22470:16;22467:1;22460:27;22275:2;;23120;23117:1;23110:13;23484:4;23466:16;23462:27;23541:4;23535;23529;23514:32;23787:2;23781:4;23777:13;23774:1;23767:24;21370:2648;24048:22;24073:42;24088:5;24095:6;24103:5;24110:4;24073:14;:42::i;:::-;24048:67;;24540:2;24531:6;24525:13;24521:22;25002:66;24995:4;24987:6;24983:17;24976:93;25111:4;25103:6;25099:17;25330:2;25324:4;25320:13;25313:5;25306:28;3408:443:26;3559:22;3595:25;3634:23;3521:6;1732:29:25;1754:6;1732:21;:29::i;:::-;3682:28:26::1;3744:22;3759:6;3744:14;:22::i;:::-;3720:46:::0;;-1:-1:-1;3720:46:26;-1:-1:-1;3806:38:26::1;3720:46:::0;3806:36:::1;:38::i;:::-;3408:443:::0;;3776:68;;-1:-1:-1;3408:443:26;-1:-1:-1;;;;3408:443:26:o;4178:301:31:-;2561:20:17;:18;:20::i;:::-;2970:18:8::1;:16;:18::i;:::-;4345:6:31::2;3418:22;3435:4;3418:16;:22::i;:::-;-1:-1:-1::0;;;;;4363:25:31;;::::3;;::::0;;;:17:::3;:25;::::0;;;;;;;:34;;::::3;::::0;;;;;;;;;;;:45;;-1:-1:-1;;4363:45:31::3;::::0;::::3;;;::::0;;4423:49;4363:25;;:34;4423:49:::3;::::0;::::3;::::0;4363:45;;4423:49:::3;:::i;:::-;;;;;;;;2998:1:8::2;2602:19:17::0;:17;:19::i;4485:155:31:-;4576:4;4599:34;4619:4;4625:7;4599:19;:34::i;:::-;4592:41;;4485:155;;;;;:::o;1074:3172:2:-;3593:66;3588:3;3581:79;;;3799:66;3793:4;3786:80;3941:1;3935:4;3928:15;2999:73;2210:2;2243:18;;;2288;;;2215:4;2284:29;;;3040:1;3036:14;2195:18;;;;3025:26;;;;2336:18;;;;2383;;;2379:29;;;3057:2;3053:17;3021:50;;;;2999:73;2994:3;2990:83;4008:4;4001:26;4234:3;;4224:14;2634:271:17;2757:48;2061:1;2766:7;;:19;;6323:3:2;2757:8:17;:48::i;:::-;2061:1;2880:7;:18;2634:271::o;2300:181:1:-;2355:16;2374:20;2386:7;;-1:-1:-1;;;;;;2386:7:1;2374:11;:20::i;:::-;2355:39;;2404:70;2413:33;2425:8;2435:10;2413:11;:33::i;:::-;6379:3:2;2404:8:1;:70::i;3911:150:31:-;3985:32;;-1:-1:-1;;;;;3985:32:31;;;;;;;;4027:11;:27;;-1:-1:-1;;;;;4027:27:31;;;;;;;;;;;;;;;3911:150::o;2911:208:17:-;2018:1;3090:7;:22;2911:208::o;4220:98:8:-;4272:39;4281:14;:12;:14::i;:::-;6423:3:2;4272:8:8;:39::i;:::-;4220:98::o;4445:381:25:-;4580:7;4650:14;;;4726:6;4705:14;4697:23;;;;;;;;4689:44;;4675:58;4784:6;4757:34;;;-1:-1:-1;;4757:34:25;4743:48;;-1:-1:-1;4445:381:25;;;;;;:::o;8950:1162:29:-;9095:17;9126:6;9146:7;9167;9188:15;9217:4;9400:14;9417:2;:9;;;9400:26;;9451:10;-1:-1:-1;;;;;9441:20:29;:6;-1:-1:-1;;;;;9441:20:29;;9437:575;;9779:22;9774:130;;9821:21;:19;:21::i;:::-;9885:4;9860:29;;9774:130;9918:83;9927:39;9947:6;9955:10;9927:19;:39::i;:::-;8156:3:2;9918:8:29;:83::i;:::-;10030:7;;10039:8;;;;10049:9;;;;10068:12;;;;;10030:7;;10039:8;;10049:9;10060:6;;-1:-1:-1;10068:12:29;;-1:-1:-1;10082:22:29;;-1:-1:-1;8950:1162:29;-1:-1:-1;;;8950:1162:29:o;5390:404::-;5660:74;5685:6;5693:25;5712:5;5693:18;:25::i;:::-;5720:6;5728:5;5660:24;:74::i;:::-;;5744:43;5755:5;5762:6;5770:9;5781:5;5744:10;:43::i;5098:286::-;5254:70;5279:9;5290:25;5309:5;5290:18;:25::i;:::-;5317:6;5254:24;:70::i;:::-;5334:43;5348:5;5355:6;5363;5371:5;5334:13;:43::i;1597:105:0:-;-1:-1:-1;;;;;1673:22:0;;;1597:105::o;367:166:11:-;425:7;456:5;;;471:37;480:6;;;;425:7;471:8;:37::i;5800:379:29:-;6058:54;6083:6;6091:5;6098:6;6106:5;6058:24;:54::i;:::-;;6122:50;6147:9;6158:5;6165:6;6122:24;:50::i;6185:329::-;6346:10;;6342:166;;6372:49;-1:-1:-1;;;;;6372:22:29;;6395:6;6403:9;6414:6;6372:22;:49::i;:::-;6471:6;-1:-1:-1;;;;;6440:57:29;6464:5;-1:-1:-1;;;;;6440:57:29;;6479:9;6490:6;6440:57;;;;;;;:::i;:::-;;;;;;;;6185:329;;;;:::o;5409:261:21:-;5477:58;5499:10;5486:9;:23;;8919:3:2;5477:8:21;:58::i;:::-;5563:9;:22;;;5599:10;;5595:69;;5625:28;:10;5646:6;5625:20;:28::i;8662:153:29:-;-1:-1:-1;;;;;8771:30:29;;;8745:7;8771:30;;;:21;:30;;;;;;;;:37;;;;;;;;;;;;;8662:153::o;3793:358:8:-;3849:6;3845:232;;;3871:81;3898:24;:22;:24::i;:::-;3880:15;:42;6481:3:2;3871:8:8;:81::i;:::-;3845:232;;;3983:83;4010:25;:23;:25::i;:::-;3992:15;:43;7911:3:2;3983:8:8;:83::i;:::-;4087:7;:16;;-1:-1:-1;;4087:16:8;;;;;;;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:8;;;;4766:8;;4544:237::o;4894:108::-;4976:19;4894:108;:::o;5008:110::-;5091:20;5008:110;:::o;5003:582:31:-;5066:10;-1:-1:-1;;;;;5066:18:31;;;5062:517;;5204:21;:19;:21::i;:::-;5439:37;5459:4;5465:10;5439:19;:37::i;:::-;5434:135;;5496:58;5515:4;8156:3:2;5496:18:31;:58::i;1874:139:0:-;1939:6;1964:13;1971:5;1964:6;:13::i;:::-;:42;;1990:16;2000:5;1990:9;:16::i;:::-;1964:42;;;1980:7;:5;:7::i;11685:1131:28:-;11799:24;11837:16;11867:17;11984:12;11999:31;12015:7;:14;;;11999:15;:31::i;:::-;11984:46;;12040:33;12076:38;12099:7;:14;;;12076:22;:38::i;:::-;12040:74;-1:-1:-1;12147:28:28;12129:14;:46;;;;;;;;;12125:500;;;12210:68;12242:7;12272:4;12210:31;:68::i;:::-;12191:87;;12125:500;;;12317:36;12299:14;:54;;;;;;;;;12295:330;;;12388:75;12427:7;12457:4;12388:38;:75::i;12295:330::-;12555:59;12586:7;12608:4;12555:30;:59::i;:::-;12536:78;;12295:330;12659:59;12671:7;:12;;;12685:7;:14;;;12701:16;12659:11;:59::i;:::-;12635:83;;;;;;;;12771:7;:16;;;-1:-1:-1;;;;;12733:76:28;12754:7;:15;;;-1:-1:-1;;;;;12733:76:28;12738:7;:14;;;12733:76;12789:8;12799:9;12733:76;;;;;;;:::i;:::-;;;;;;;;11685:1131;;;;;;;:::o;1883:1514:21:-;2039:11;2035:48;;2066:7;;2035:48;2097:13;2104:5;2097:6;:13::i;:::-;2093:1298;;;2126:67;2136:19;2135:20;8802:3:2;2126:8:21;:67::i;:::-;2580:66;2614:6;2589:21;:31;;8919:3:2;2580:8:21;:66::i;:::-;2660:7;:5;:7::i;:::-;-1:-1:-1;;;;;2660:15:21;;2684:6;2660:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2093:1298;;;2725:12;2740:16;2750:5;2740:9;:16::i;:::-;2725:31;;2775:19;2771:494;;;2934:23;2960:53;2985:6;2993:5;3000:6;3008:4;2960:24;:53::i;:::-;3225:25;;;;-1:-1:-1;2771:494:21;3283:10;;3279:102;;3313:53;-1:-1:-1;;;;;3313:22:21;;3336:6;3352:4;3359:6;3313:22;:53::i;:::-;2093:1298;1883:1514;;;;:::o;3767:1086::-;3929:11;3925:48;;3956:7;;3925:48;3987:13;3994:5;3987:6;:13::i;:::-;3983:864;;;4167:65;4177:17;4176:18;8802:3:2;4167:8:21;:65::i;:::-;4448:7;:5;:7::i;:::-;-1:-1:-1;;;;;4448:16:21;;4465:6;4448:24;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4552:27:21;;-1:-1:-1;;;;;;;;4552:19:21;;4572:6;4552:19;:27::i;:::-;3983:864;;;4610:12;4625:16;4635:5;4625:9;:16::i;:::-;4610:31;;4659:17;4655:182;;;4696:50;4721:9;4732:5;4739:6;4696:24;:50::i;:::-;4655:182;;;4785:37;-1:-1:-1;;;;;4785:18:21;;4804:9;4815:6;4785:18;:37::i;855:131:6:-;933:46;947:1;942;:6;5002:3:2;933:8:6;:46::i;1925:405:22:-;2002:7;2195:18;2216:26;:24;:26::i;:::-;-1:-1:-1;;;;;2216:52:22;;:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2195:75;;2287:36;2304:6;2312:10;2287:16;:36::i;605:214:19:-;717:95;745:5;776:23;;;801:2;805:5;753:58;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;753:58:19;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;753:58:19;;;;;;;;;;717:19;:95::i;2336:182:22:-;2412:10;;2408:104;;2438:63;2465:26;:24;:26::i;:::-;-1:-1:-1;;;;;2438:18:22;;;2494:6;2438:18;:63::i;2359:185:25:-;2427:29;2449:6;2427:21;:29::i;:::-;2466:71;2489:23;2505:6;2489:15;:23::i;:::-;-1:-1:-1;;;;;2475:37:25;:10;-1:-1:-1;;;;;2475:37:25;;8031:3:2;2466:8:25;:71::i;5510:1061::-;5581:33;5781:14;5769:6;5758:18;;;5750:46;6278:43;6295:1;6287:9;;7978:3:2;6278:8:25;:43::i;3805:982:35:-;4091:59;4110:6;-1:-1:-1;;;;;4100:16:35;:6;-1:-1:-1;;;;;4100:16:35;;;9256:3:2;4091:8:35;:59::i;:::-;4161:49;4179:6;-1:-1:-1;;;;;4170:15:35;:6;-1:-1:-1;;;;;4170:15:35;;4943:3:2;4161:8:35;:49::i;:::-;4334:37;4374:27;;;:19;:27;;;;;4420:17;;4411:101;;-1:-1:-1;;;;;4420:17:35;:30;:64;;;;-1:-1:-1;4454:17:35;;;;-1:-1:-1;;;;;4454:17:35;:30;4420:64;9312:3:2;4411:8:35;:101::i;:::-;4585:26;;-1:-1:-1;;;;;4585:26:35;;;-1:-1:-1;;;;;;4585:26:35;;;;;;;4621:17;;;:26;;;;;;;;;;;-1:-1:-1;3805:982:35:o;2280:519:34:-;2383:43;2429:35;;;:27;:35;;;;;;2475:318;2499:6;:13;2495:1;:17;2475:318;;;2533:10;2546:34;2569:6;2576:1;2569:9;;;;;;;;;;;;;;2546:10;:14;;:34;;;;:::i;:::-;2533:47;;2594:48;2603:5;9256:3:2;2594:8:34;:48::i;:::-;-1:-1:-1;2514:3:34;;2475:318;;2330:589:33;2425:53;2481:29;;;:21;:29;;;;;;2521:392;2545:6;:13;2541:1;:17;2521:392;;;2797:10;2810:30;2827:6;2834:1;2827:9;;;;;;;;;;;;;;;;;;2810:12;;2838:1;2810:16;:30::i;:::-;2797:43;;2854:48;2863:5;9256:3:2;2854:8:33;:48::i;:::-;-1:-1:-1;2560:3:33;;2521:392;;5124:666:35;5272:16;5302;5332:41;5386:54;5417:6;5425;5433;5386:30;:54::i;:::-;5258:182;;;;;;5451:78;5460:17;:8;:15;:17::i;:::-;:38;;;;;5481:17;:8;:15;:17::i;:::-;9432:3:2;5451:8:35;:78::i;:::-;5547:27;;;;:19;:27;;;;;5540:34;;-1:-1:-1;;;;;;5540:34:35;;;;;;;;;;;;;;;;5753:30;;;;-1:-1:-1;;;;5124:666:35:o;3192:758:34:-;3297:43;3343:35;;;:27;:35;;;;;;3389:555;3413:6;:13;3409:1;:17;3389:555;;;3447:12;3462:6;3469:1;3462:9;;;;;;;;;;;;;;3447:24;;3485:93;3494:53;:29;:37;3524:6;3494:37;;;;;;;;;;;:44;3532:5;-1:-1:-1;;;;;3494:44:34;-1:-1:-1;;;;;3494:44:34;;;;;;;;;;;;;:51;:53::i;3485:93::-;3766:37;;;;:29;:37;;;;;;;;-1:-1:-1;;;;;3766:44:34;;;;;;;;;3759:51;;;3840:33;:10;3804:5;3840:17;:33::i;:::-;3825:48;;3887:46;3896:7;9194:3:2;3887:8:34;:46::i;:::-;-1:-1:-1;;3428:3:34;;3389:555;;3292:643:33;3389:53;3445:29;;;:21;:29;;;;;;3485:444;3509:6;:13;3505:1;:17;3485:444;;;3543:12;3558:6;3565:1;3558:9;;;;;;;;;;;;;;3543:24;;3581:22;3606:43;3629:12;3643:5;3606:22;:43::i;:::-;3581:68;;3663:63;3672:23;:14;:21;:23::i;3663:63::-;3892:26;:12;3912:5;3892:19;:26::i;:::-;;3485:444;;3524:3;;;;;3485:444;;3614:267:24;3722:31;;:::i;:::-;-1:-1:-1;3858:7:24;3834:41::o;3975:2358::-;2561:20:17;:18;:20::i;:::-;4202:6:24::1;1732:29:25;1754:6;1732:21;:29::i;:::-;4226:6:24::2;3418:22:31;3435:4;3418:16;:22::i;:::-;4533:79:24::3;4569:6;:13;;;:20;4591:6;:13;;;:20;4533:35;:79::i;:::-;4777:22;4802:33;4821:6;:13;;;4802:18;:33::i;:::-;4777:58;;4845:25;4873:45;4903:6;4911;4873:29;:45::i;:::-;4845:73;;5115:30;5159:31:::0;5204:43:::3;5260:73;5283:4;5289:6;5297;5305:9;5316:6;5324:8;5260:22;:73::i;:::-;5101:232;;;;;;5406:33;5442:30;5465:6;5442:22;:30::i;:::-;5406:66:::0;-1:-1:-1;5504:28:24::3;5486:14;:46;;;;;;;;;5482:443;;;5548:94;5577:6;5585;5592:1;5585:9;;;;;;;;;;;;;;5596:13;5610:1;5596:16;;;;;;;;;;;;;;5614:6;5621:1;5614:9;;;;;;;;;;;;;;5625:13;5639:1;5625:16;;;;;;;;;;;;;;5548:28;:94::i;:::-;5482:443;;;5681:36;5663:14;:54;;;;;;;;;5659:266;;;5733:62;5765:6;5773;5781:13;5733:31;:62::i;5659:266::-;5868:46;5892:6;5900:13;5868:23;:46::i;:::-;5935:13;::::0;5951:4:::3;:34;;;;;;;;;5935:50;;6097:6;-1:-1:-1::0;;;;;6045:281:24::3;6077:6;6045:281;6117:6;6231:45;6251:14;6267:8;6231:19;:45::i;:::-;6290:26;6045:281;;;;;;;;:::i;:::-;;;;;;;;3450:1:31;;;;;;;1771::25::2;2591::17::1;2602:19:::0;:17;:19::i;8232:3150:28:-;8409:27;8475:6;:13;8462:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;8462:27:28;;8448:41;;8667:34;;:::i;:::-;8711:47;;:::i;:::-;8868:30;8908:32;8956:9;8951:2425;8975:5;:12;8971:1;:16;8951:2425;;;9024:5;9030:1;9024:8;;;;;;;;;;;;;;9008:24;;9047:17;9096:6;:13;9067;:26;;;:42;:105;;;;;9159:6;:13;9129;:27;;;:43;9067:105;9047:125;;9186:44;9195:12;4838:3:2;9186:8:28;:44::i;:::-;9245:14;9262:54;9281:6;9288:13;:26;;;9281:34;;;;;;;;;;;;;;9262:18;:54::i;:::-;9245:71;;9330:15;9348:55;9367:6;9374:13;:27;;;9367:35;;;;;;;9348:55;9330:73;;9417:60;9437:8;-1:-1:-1;;;;;9426:19:28;:7;-1:-1:-1;;;;;9426:19:28;;;8474:3:2;9417:8:28;:60::i;:::-;9545:20;;;;9541:720;;9939:52;9952:1;9948;:5;8540:3:2;9939:8:28;:52::i;:::-;10009:23;10062:36;10074:4;10080:7;10089:8;10062:11;:36::i;:::-;-1:-1:-1;;;;;10035:63:28;:23;-1:-1:-1;;;;;10035:63:28;;10009:89;;10116:65;10125:18;8606:3:2;10116:8:28;:65::i;:::-;-1:-1:-1;10199:20:28;;;:47;;;9541:720;10392:20;;10371:18;;;:41;:11;10445:4;10426:23;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;10463:29:28;;;:19;;;:29;10506:31;;;:20;;;;:31;;;;10572:20;;;;;10551:18;;;:41;10629:22;;;;10606:20;;;:45;10684:12;;10665:31;;:16;;;:31;10727:15;;;10710:32;:14;;;:32;-1:-1:-1;;10931:26:28;10463:11;10931:13;:26::i;:::-;10881:76;;-1:-1:-1;10881:76:28;-1:-1:-1;10881:76:28;-1:-1:-1;10998:41:28;11015:4;11021:7;11030:8;10998:16;:41::i;:::-;10972:67;;11148:64;11192:19;:8;:17;:19::i;:::-;11148:11;11160:13;:26;;;11148:39;;;;;;;;;;;;;;:43;;:64;;;;:::i;:::-;11106:11;11118:13;:26;;;11106:39;;;;;;;;;;;;;:106;;;;;11269:96;11331:20;:9;:18;:20::i;:::-;11269:11;11281:13;:27;;;11269:40;;;;;;;;;;;;;;:44;;:96;;;;:::i;:::-;11226:11;11238:13;:27;;;11226:40;;;;;;;;;;;;;:139;;;;;8951:2425;;;;;8989:3;;;;;8951:2425;;;;8232:3150;;;;;;;;;;:::o;2091:137:25:-;2171:25;;;;:17;:25;;;;;;2162:59;;2171:25;;7978:3:2;2162:8:25;:59::i;12286:636:35:-;12372:7;12610:13;12625:16;12643:13;12658:16;12678:32;12703:6;12678:24;:32::i;:::-;12607:103;;;;;;;;;12734:6;-1:-1:-1;;;;;12725:15:35;:5;-1:-1:-1;;;;;12725:15:35;;12721:195;;;12763:8;12756:15;;;;;;;;12721:195;12801:6;-1:-1:-1;;;;;12792:15:35;:5;-1:-1:-1;;;;;12792:15:35;;12788:128;;;12830:8;-1:-1:-1;12823:15:35;;-1:-1:-1;;;12823:15:35;12788:128;12869:36;9194:3:2;12869:7:35;:36::i;:::-;12286:636;;;;;;;;:::o;8346:898:34:-;8439:7;8476:37;;;:29;:37;;;;;;;;-1:-1:-1;;;;;8476:44:34;;;;;;;;;;8439:7;8830:19;8476:44;8830:17;:19::i;:::-;:83;;;-1:-1:-1;8853:35:34;;;;:27;:35;;;;;:60;;8906:5;8853:44;:60::i;:::-;8807:106;;8929:15;8924:289;;9123:29;9145:6;9123:21;:29::i;:::-;9166:36;9194:3:2;9166:7:34;:36::i;:::-;-1:-1:-1;9230:7:34;8346:898;-1:-1:-1;;;8346:898:34:o;8359:256:33:-;8444:7;8519:29;;;:21;:29;;;;;8565:43;8519:29;8602:5;8565:22;:43::i;3700:147:32:-;3788:12;3817:23;;3700:147::o;3959:157::-;4098:3;4087:14;4050:12;4079:30;;3959:157::o;4205:164::-;4351:3;4340:14;;4205:164::o;7130:581:20:-;7210:4;7226:33;7262:30;7285:6;7262:22;:30::i;:::-;7226:66;-1:-1:-1;7324:28:20;7306:14;:46;;;;;;;;;7302:403;;;7375:45;7406:6;7414:5;7375:30;:45::i;:::-;7368:52;;;;;7302:403;7459:36;7441:14;:54;;;;;;;;;7437:268;;;7518:52;7556:6;7564:5;7518:37;:52::i;7437:268::-;7650:44;7680:6;7688:5;7650:29;:44::i;3038:679::-;3204:6;3212;3230:33;3266:30;3289:6;3266:22;:30::i;:::-;3230:66;-1:-1:-1;3319:26:20;3311:4;:34;;;;;;;;;3307:404;;;3368:59;3389:6;3397:14;3413:5;3420:6;3368:20;:59::i;:::-;3361:66;;;;;;;3307:404;3456:25;3448:4;:33;;;;;;;;;3444:267;;;3504:58;3524:6;3532:14;3548:5;3555:6;3504:19;:58::i;3444:267::-;3640:60;3662:6;3670:14;3686:5;3693:6;3640:21;:60::i;3038:679::-;;;;;;;;:::o;2386:188:13:-;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;5009:314:25:-;5308:6;5288:27;;5009:314::o;4951:564:26:-;5014:22;5038:25;5075:33;5111:30;5134:6;5111:22;:30::i;:::-;5075:66;-1:-1:-1;5173:28:26;5155:14;:46;;;;;;;;;5151:358;;;5224:30;5247:6;5224:22;:30::i;:::-;5217:37;;;;;;;5151:358;5293:36;5275:14;:54;;;;;;;;;5271:238;;;5352:37;5382:6;5352:29;:37::i;5271:238::-;5469:29;5491:6;5469:21;:29::i;4951:564::-;;;;:::o;4919:539:32:-;5040:24;5078;5170:8;:15;5156:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5156:30:32;;5146:40;;5215:1;5196:20;;5232:9;5227:225;5251:7;:14;5247:1;:18;5227:225;;;5286:15;5304:8;5313:1;5304:11;;;;;;;;;;;;;;5286:29;;5342:14;5348:7;5342:5;:14::i;:::-;5329:7;5337:1;5329:10;;;;;;;;;;;;;:27;;;;;5389:52;5398:16;5416:24;5432:7;5416:15;:24::i;:::-;5389:8;:52::i;:::-;5370:71;-1:-1:-1;;5267:3:32;;5227:225;;5691:145:31;-1:-1:-1;;;;;5797:23:31;;;5774:4;5797:23;;;:17;:23;;;;;;;;:32;;;;;;;;;;;;;;;5691:145::o;5842:226::-;6008:11;;:53;;;;;5927:4;;6008:11;;;-1:-1:-1;;;;;6008:11:31;;:22;;:53;;6031:8;;6041:4;;6055;;6008:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;7222:684:29:-;7387:16;7415:22;7440:35;7460:7;7469:5;7440:19;:35::i;:::-;7415:60;;7485:90;7494:12;:42;;;;7529:6;7511:14;:24;;7494:42;8736:3:2;7485:8:29;:90::i;:::-;7597:32;7606:14;7622:6;7597:8;:32::i;:::-;7586:43;-1:-1:-1;7793:25:29;;;7828:71;7848:7;7857:5;7793:25;7878:19;7586:43;7878:17;:19::i;:::-;7876:22;;7828:19;:71::i;:::-;7222:684;;;;;;;;:::o;6612:339::-;6751:22;6776:35;6796:7;6805:5;6776:19;:35::i;:::-;6751:60;-1:-1:-1;6821:18:29;6842:26;6751:60;6861:6;6842:18;:26::i;:::-;6821:47;;6878:66;6898:7;6907:5;6914:10;6926:17;:6;:15;:17::i;:::-;6878:19;:66::i;825:250:19:-;963:105;991:5;1022:27;;;1051:4;1057:2;1061:5;999:68;;;;;;;;;;:::i;2109:369:12:-;2190:78;2224:6;2199:21;:31;;7534:3:2;2190:8:12;:78::i;:::-;2357:12;2375:9;-1:-1:-1;;;;;2375:14:12;2398:6;2375:35;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2356:54;;;2420:51;2429:7;7597:3:2;2420:8:12;:51::i;2115:190:7:-;-1:-1:-1;;;;;2215:16:7;;2195:17;2215:16;;;:10;:16;;;;;:18;;;;;;;;2243:55;2252:34;2226:4;2215:18;2252:17;:34::i;:::-;2288:9;2243:8;:55::i;12822:1849:28:-;12968:24;13223:21;13258;13293:41;13347:81;13378:7;:14;;;13394:7;:15;;;13411:7;:16;;;13347:30;:81::i;:::-;13209:219;;;;;;13539:22;13571:23;13701:7;:16;;;-1:-1:-1;;;;;13683:34:28;:7;:15;;;-1:-1:-1;;;;;13683:34:28;;13679:312;;;-1:-1:-1;13783:13:28;;-1:-1:-1;13828:13:28;13679:312;;;-1:-1:-1;13967:13:28;;-1:-1:-1;13923:13:28;13679:312;14166:140;14214:7;14235:4;14253:14;14281:15;14166:34;:140::i;:::-;14450:16;;;;14432:15;;;;14112:194;;-1:-1:-1;14112:194:28;;-1:-1:-1;14112:194:28;;-1:-1:-1;;;;;;14432:34:28;;;;;;:211;;14580:63;14611:15;14628:14;14580:30;:63::i;:::-;14432:211;;;14481:63;14512:14;14528:15;14481:30;:63::i;:::-;14406:237;;;-1:-1:-1;12822:1849:28;;;-1:-1:-1;;;;;12822:1849:28:o;14677:887::-;14836:24;14872:22;14897:63;14928:7;:14;;;14944:7;:15;;;14897:30;:63::i;:::-;14872:88;;14970:23;14996:64;15027:7;:14;;;15043:7;:16;;;14996:30;:64::i;:::-;14970:90;;15236:140;15284:7;15305:4;15323:14;15351:15;15236:34;:140::i;:::-;15417:14;;;;;15387:45;;;;:29;:45;;;;;;;;15433:15;;;;-1:-1:-1;;;;;15387:62:28;;;;;;;;;;;:79;;;;15506:14;;15476:45;;;;;;;;15522:16;;;;15476:63;;;;;;;;;;;;;:81;;;;-1:-1:-1;15182:194:28;;14677:887;-1:-1:-1;;;14677:887:28:o;16781:2740::-;17220:14;;;;16918:24;17198:37;;;:21;:37;;;;;;;17294:15;;;;16918:24;;;;;;17263:47;;17198:37;;17263:30;:47::i;:::-;17245:65;;17320:16;17339:48;17370:7;:16;;;17339:12;:30;;:48;;;;:::i;:::-;17320:67;-1:-1:-1;17402:12:28;;;:29;;-1:-1:-1;17418:13:28;;17402:29;17398:311;;;17611:37;17633:7;:14;;;17611:21;:37::i;:::-;17662:36;9194:3:2;17662:7:28;:36::i;:::-;-1:-1:-1;;17868:12:28;;;;17890:13;17914:19;17936:21;:12;:19;:21::i;:::-;17914:43;;17967:32;18016:11;18002:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;18002:26:28;-1:-1:-1;18065:1:28;18039:23;;;:27;;;17967:61;;-1:-1:-1;18076:663:28;18100:11;18096:1;:15;18076:663;;;18354:15;18372:33;:12;18403:1;18372:30;:33::i;:::-;18354:51;;18441:15;:7;:13;:15::i;:::-;18420;18436:1;18420:18;;;;;;;;;;;;;:36;;;;;18496:60;18505:7;:23;;;18530:25;:7;:23;:25::i;18496:60::-;18470:23;;;:86;18575:12;;;18571:158;;;18624:7;18607:24;;18571:158;;;18661:8;18656:1;:13;18652:77;;;18707:7;18689:25;;18652:77;-1:-1:-1;18113:3:28;;18076:663;;;-1:-1:-1;18888:56:28;;;;;-1:-1:-1;;;;;18888:11:28;;;;;:56;;18900:7;;18909:15;;18926:7;;18935:8;;18888:56;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18869:75;;18955:16;18973:17;18994:59;19006:7;:12;;;19020:7;:14;;;19036:16;18994:11;:59::i;:::-;18954:99;;-1:-1:-1;18954:99:28;-1:-1:-1;19080:37:28;:14;18954:99;19080:27;:37::i;:::-;19063:54;-1:-1:-1;19145:39:28;:15;19174:9;19145:28;:39::i;:::-;19127:57;-1:-1:-1;19396:53:28;:12;19425:7;19434:14;19396:28;:53::i;:::-;19459:55;:12;19488:8;19498:15;19459:28;:55::i;:::-;16781:2740;;;;;;;;;;;;;:::o;7504:419::-;7639:16;;;7690:4;:25;;;;;;;;;7686:231;;;-1:-1:-1;7756:11:28;;-1:-1:-1;7769:16:28;7686:231;;;-1:-1:-1;7876:16:28;;-1:-1:-1;7894:11:28;7686:231;7504:419;;;;;;:::o;1862:617:9:-;1922:7;1959:5;;;1974:57;1983:6;;;:26;;;2008:1;2003;1993:7;:11;;;;;;:16;1983:26;4467:1:2;1974:8:9;:57::i;:::-;2046:12;2042:431;;2081:1;2074:8;;;;;2042:431;893:4;-1:-1:-1;;2439:11:9;;2438:19;2461:1;2437:25;2430:32;;;;;1415:799:19;1658:12;1672:23;1699:5;-1:-1:-1;;;;;1699:10:19;1710:4;1699:16;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1657:58;;;;1853:1;1844:7;1841:14;1838:2;;;1895:16;1892:1;1889;1874:38;1939:16;1936:1;1929:27;1838:2;2110:97;2119:10;:17;2140:1;2119:22;:56;;;;2156:10;2145:30;;;;;;;;;;;;:::i;:::-;7468:3:2;2110:8:19;:97::i;1803:410:15:-;1873:4;1894:20;1903:3;1908:5;1894:8;:20::i;:::-;1889:318;;-1:-1:-1;1930:23:15;;;;;;;;-1:-1:-1;1930:23:15;;;;;;;;;;;;-1:-1:-1;;;;;;1930:23:15;-1:-1:-1;;;;;1930:23:15;;;;;;;;2110:18;;2088:19;;;:12;;;:19;;;;;;:40;;;;2142:11;;1889:318;-1:-1:-1;2191:5:15;2184:12;;2481:859:14;-1:-1:-1;;;;;2734:17:14;;2601:4;2734:17;;;:12;;;:17;;;;;;2811:13;2807:527;;-1:-1:-1;;2865:11:14;;2921:53;;;;;;;;-1:-1:-1;;;;;2921:53:14;;;;;;;;;;;;;-1:-1:-1;2890:28:14;;;:12;;;;:28;;;;;:84;;;;-1:-1:-1;;;;;;2890:84:14;;;;;;;;;;;;;;;;;;3002:18;;;2988:32;;;3162:17;;;:12;;;:17;;;;;;:38;;;;3214:11;;2807:527;-1:-1:-1;;3269:12:14;3256:26;;;;:12;;;;:26;;;;;:33;:41;;;:26;-1:-1:-1;3311:12:14;;13539:1758:35;13715:16;13745;13775:41;13842:13;13857;13874:30;13889:6;13897;13874:14;:30::i;:::-;13841:63;;;;13914:16;13933:36;13954:6;13962;13933:20;:36::i;:::-;13995:27;;;;:19;:27;;;;;;;;:46;;;:36;;:46;;;;;14236:23;;14293:26;;;;13995:46;;-1:-1:-1;13914:55:35;;-1:-1:-1;14293:26:35;14639:22;14236:23;14639:20;:22::i;:::-;:63;;;;14677:25;:13;:23;:25::i;:::-;14639:177;;;;14719:46;14750:6;14758;14719:30;:46::i;:::-;:96;;;;;14769:46;14800:6;14808;14769:30;:46::i;:::-;14615:201;;14832:16;14827:291;;15028:29;15050:6;15028:21;:29::i;:::-;15071:36;9194:3:2;15071:7:35;:36::i;:::-;15139:65;15178:10;15190:13;15139:38;:65::i;:::-;15128:76;;15225:65;15264:10;15276:13;15225:38;:65::i;:::-;15214:76;;13539:1758;;;;;;;;;;;;;:::o;5615:265:32:-;5814:12;5844:23;5843:30;;5615:265::o;2381:1531:15:-;-1:-1:-1;;;;;2591:19:15;;2454:4;2591:19;;;:12;;;:19;;;;;;2625:15;;2621:1285;;3066:18;;-1:-1:-1;;3018:14:15;;;;3066:22;;;;2994:21;;3066:3;;:22;;3348;;;;;;;;;;;;;;;;3462:26;;-1:-1:-1;;;;;3348:22:15;;;;-1:-1:-1;3348:22:15;;3462:3;;3474:13;;3462:26;;;;;;;;;;;;;;;;;;:38;;-1:-1:-1;;;;;;3462:38:15;-1:-1:-1;;;;;3462:38:15;;;;;;3566:23;;;;;-1:-1:-1;3566:12:15;;;:23;;;;;;3592:17;;;3566:43;;3715:17;;3566:12;;3715:17;;;;;;;;;;;;;;;-1:-1:-1;;3715:17:15;;;;;-1:-1:-1;;;;;;3715:17:15;;;;;;;;;-1:-1:-1;;;;;3807:19:15;;;;3715:17;3807:12;;;:19;;;;;;3800:26;;;;3715:17;-1:-1:-1;3841:11:15;;-1:-1:-1;;;;3841:11:15;2621:1285;3890:5;3883:12;;;;;8771:236:33;8918:7;8948:52;:12;8965:5;9194:3:2;8948:16:33;:52::i;4074:1613:14:-;-1:-1:-1;;;;;4285:17:14;;4152:4;4285:17;;;:12;;;:17;;;;;;4361:13;;4357:1324;;4769:11;;-1:-1:-1;;4769:15:14;;;4699:21;5068:23;;;4734:1;5068:12;;;:23;;;;;;;;4723:12;;;5183:27;;;;;:39;;;;-1:-1:-1;;;;;;5183:39:14;;;-1:-1:-1;;;;;5183:39:14;;;;;;;;;;;;;;;;;;5301:14;;;;5288:28;;:12;;;:28;;;;;;:48;;;;5442:30;;;;;;;;;5486:23;;;5584:17;;;;;;;;;;;5577:24;4734:1;-1:-1:-1;5616:11:14;;2110:303:0;2185:15;2212:22;2250:6;:13;2237:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2237:27:0;;2212:52;;2279:9;2274:110;2298:6;:13;2294:1;:17;2274:110;;;2344:29;2363:6;2370:1;2363:9;;;;;;;2344:29;2332:6;2339:1;2332:9;;;;;;;;-1:-1:-1;;;;;2332:41:0;;;:9;;;;;;;;;;;:41;2313:3;;2274:110;;11958:590:24;12091:16;12124:28;12154:25;12183:22;12198:6;12183:14;:22::i;:::-;12123:82;;;;12215:79;12251:12;:19;12272:14;:21;12215:35;:79::i;:::-;12304:56;12335:1;12313:12;:19;:23;9544:3:2;12304:8:24;:56::i;:::-;12376:9;12371:145;12395:12;:19;12391:1;:23;12371:145;;;12435:70;12463:14;12478:1;12463:17;;;;;;;;;;;;;;-1:-1:-1;;;;;12444:36:24;:12;12457:1;12444:15;;;;;;;;;;;;;;-1:-1:-1;;;;;12444:36:24;;9136:3:2;12435:8:24;:70::i;:::-;12416:3;;12371:145;;;-1:-1:-1;12533:8:24;11958:590;-1:-1:-1;;;;11958:590:24:o;6560:1752::-;6839:30;6883:31;6928:38;6992:30;7024:23;7051:35;:8;:33;:35::i;:::-;6991:95;;;;7097:14;7124:23;7140:6;7124:15;:23::i;:::-;7097:51;-1:-1:-1;7208:26:24;7200:4;:34;;;;;;;;;:564;;7514:4;-1:-1:-1;;;;;7514:15:24;;7547:6;7571;7595:9;7622:13;7653:15;7686:31;:29;:31::i;:::-;7735:6;:15;;;7514:250;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;7514:250:24;;;;;;;;;;;;:::i;:::-;7200:564;;;7249:4;-1:-1:-1;;;;;7249:15:24;;7282:6;7306;7330:9;7357:13;7388:15;7421:31;:29;:31::i;:::-;7470:6;:15;;;7249:250;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;7249:250:24;;;;;;;;;;;;:::i;:::-;7158:606;;;;;;;;7775:105;7811:8;:15;7828:14;:21;7851;:28;7775:35;:105::i;:::-;8066:26;8058:4;:34;;;;;;;;;:247;;8212:93;8238:9;8249:6;8257:8;8267:14;8283:21;8212:25;:93::i;:::-;8058:247;;;8107:90;8133:6;8141;8149:8;8159:14;8175:21;8107:25;:90::i;:::-;8042:263;;6560:1752;;;;;;;;;;;;;:::o;6003:433:35:-;6188:16;6207:36;6228:6;6236;6207:20;:36::i;:::-;6253:41;6297:27;;;:19;:27;;;;;;;;:46;;;:36;;:46;;;;;6188:55;;-1:-1:-1;6379:50:35;6410:8;6420;6379:30;:50::i;:::-;6353:76;;-1:-1:-1;;;;;;6003:433:35:o;4153:294:34:-;4315:9;4310:131;4334:6;:13;4330:1;:17;4310:131;;;4419:8;4428:1;4419:11;;;;;;;;;;;;;;4368:29;:37;4398:6;4368:37;;;;;;;;;;;:48;4406:6;4413:1;4406:9;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4368:48:34;;;;;;;;;;;-1:-1:-1;4368:48:34;:62;4349:3;;4310:131;;4128:471:33;4223:53;4279:29;;;:21;:29;;;;;;4319:274;4343:8;:15;4339:1;:19;4319:274;;;4538:44;4567:1;4570:8;4579:1;4570:11;;;;;;;;;;;;;;4538:12;:28;;:44;;;;;:::i;:::-;4360:3;;4319:274;;12760:353:24;12875:28;12947:6;:13;12934:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12934:27:24;;12919:42;;12976:9;12971:136;12995:6;:13;12991:1;:17;12971:136;;;13047:8;:49;;13086:6;13093:1;13086:9;;;;;;;;;;;;;;13078:18;;13047:49;;;13065:6;13072:1;13065:9;;;;;;;;;;;;;;13047:49;13029:12;13042:1;13029:15;;;;;;;;;;;;;;;;;:67;13010:3;;12971:136;;6776:199:28;6897:6;;6922:4;:25;;;;;;;;;:46;;6960:8;6922:46;;;-1:-1:-1;6950:7:28;;6915:53;-1:-1:-1;;6776:199:28:o;7157:204::-;7283:6;;7308:4;:25;;;;;;;;;:46;;7347:7;7308:46;;1002:175:18;1058:6;1076:64;1093:6;1085:5;:14;7666:3:2;1076:8:18;:64::i;635:194:11:-;691:6;720:5;;;735:69;745:6;;;;;;:16;;;760:1;755;:6;;745:16;744:38;;;;771:1;767;:5;:14;;;;;780:1;776;:5;767:14;4322:1:2;735:8:11;:69::i;1219:194::-;1275:6;1304:5;;;1319:69;1329:6;;;;;;:16;;;1344:1;1339;:6;;1329:16;1328:38;;;;1355:1;1351;:5;:14;;;;;1364:1;1360;:5;1351:14;4370:1:2;1319:8:11;:69::i;10934:843:35:-;11043:41;11263:27;;;:19;:27;;;;;11309:17;;;11345;;;-1:-1:-1;;;;;11309:17:35;;;;11043:41;;11345:17;;;;11043:41;;;11392:36;11309:17;11345;11392:20;:36::i;:::-;11453:29;;;;:19;;;:29;;;;;11514:23;;11571:26;;;;11453:29;;-1:-1:-1;11373:55:35;;-1:-1:-1;11619:65:35;11514:23;11571:26;11619:38;:65::i;:::-;11608:76;;11705:65;11744:10;11756:13;11705:38;:65::i;:::-;11694:76;;10934:843;;;;;;;;;;;:::o;6041:105:32:-;6100:4;6124:15;6131:7;6124:6;:15::i;:::-;6123:16;;6041:105;-1:-1:-1;;6041:105:32:o;3993:134:15:-;-1:-1:-1;;;;;4096:19:15;4073:4;4096:19;;;:12;;;;;:19;;;;;;:24;;;3993:134::o;15499:342:35:-;15592:4;15648:27;;;:19;:27;;;;;15764:17;;-1:-1:-1;;;;;15755:26:35;;;15764:17;;15755:26;;:56;;-1:-1:-1;15794:17:35;;;;-1:-1:-1;;;;;15785:26:35;;;15794:17;;15785:26;15755:56;15754:80;;;;-1:-1:-1;;;;;;;;15816:18:35;;;;15499:342;-1:-1:-1;15499:342:35:o;9462:256:34:-;9562:4;9624:35;;;:27;:35;;;;;9676;9624;9704:5;9676:19;:35::i;9205:245:33:-;9297:4;9369:29;;;:21;:29;;;;;9415:28;9369:29;9437:5;9415:21;:28::i;3967:952:20:-;4133:16;;4204:28;4186:14;:46;;;;;;;;;4182:394;;;4248:49;4275:6;4283:5;4290:6;4248:26;:49::i;:::-;4182:394;;;4336:36;4318:14;:54;;;;;;;;;4314:262;;;4388:56;4422:6;4430:5;4437:6;4388:33;:56::i;4314:262::-;4517:48;4543:6;4551:5;4558:6;4517:25;:48::i;:::-;4590:10;;4586:79;;4616:38;-1:-1:-1;;;;;4616:18:20;;4635:10;4647:6;4616:18;:38::i;:::-;-1:-1:-1;;4865:7:20;;;;;4866:6;;-1:-1:-1;3967:952:20;-1:-1:-1;;3967:952:20:o;5171:970::-;5336:16;;5407:28;5389:14;:46;;;;;;;;;5385:394;;;5451:49;5478:6;5486:5;5493:6;5451:26;:49::i;:::-;5385:394;;;5539:36;5521:14;:54;;;;;;;;;5517:262;;;5591:56;5625:6;5633:5;5640:6;5591:33;:56::i;5517:262::-;5720:48;5746:6;5754:5;5761:6;5720:25;:48::i;:::-;5793:10;;5789:98;;5819:57;-1:-1:-1;;;;;5819:22:20;;5842:10;5862:4;5869:6;5819:22;:57::i;:::-;-1:-1:-1;6087:6:20;;6126:7;;;;;-1:-1:-1;5171:970:20;-1:-1:-1;;;5171:970:20:o;6347:697::-;6514:16;;6585:28;6567:14;:46;;;;;;;;;6563:451;;;6644:53;6675:6;6683:5;6690:6;6644:30;:53::i;:::-;6629:68;;6563:451;;;6736:36;6718:14;:54;;;;;;;;;6714:300;;;6803:60;6841:6;6849:5;6856:6;6803:37;:60::i;6714:300::-;6951:52;6981:6;6989:5;6996:6;6951:29;:52::i;:::-;6936:67;;6714:300;7036:1;7024:13;;6347:697;;;;;;;:::o;3388:427:13:-;3790:9;;3765:44::o;9748:864:35:-;9843:22;9867:25;9911:13;9926:16;9944:13;9959:16;9979:32;10004:6;9979:24;:32::i;:::-;9908:103;;-1:-1:-1;9908:103:35;;-1:-1:-1;9908:103:35;-1:-1:-1;9908:103:35;-1:-1:-1;;;;;;;10167:19:35;;;;:42;;-1:-1:-1;;;;;;10190:19:35;;;10167:42;10163:115;;;-1:-1:-1;;10233:15:35;;;10246:1;10233:15;;;;;;10250:16;;;;;;;;;10233:15;-1:-1:-1;10233:15:35;-1:-1:-1;10225:42:35;;-1:-1:-1;;10225:42:35;10163:115;10432:15;;;10445:1;10432:15;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10432:15:35;10423:24;;10469:6;10457;10464:1;10457:9;;;;;;;;;;;;;:18;-1:-1:-1;;;;;10457:18:35;;;-1:-1:-1;;;;;10457:18:35;;;;;10497:6;10485;10492:1;10485:9;;;;;;;;-1:-1:-1;;;;;10485:18:35;;;;:9;;;;;;;;;;:18;10525:16;;;10539:1;10525:16;;;;;;;;;;10539:1;;10525:16;;;;;;;;;;-1:-1:-1;10525:16:35;10514:27;;10565:8;10551;10560:1;10551:11;;;;;;;;;;;;;:22;;;;;10597:8;10583;10592:1;10583:11;;;;;;;;;;;;;:22;;;;;9748:864;;;;;;;:::o;7319:799:34:-;7486:43;7532:35;;;:27;:35;;;;;7421:22;;;;7599:19;7532:35;7599:17;:19::i;:::-;7586:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7586:33:34;;7577:42;;7654:6;:13;7640:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7640:28:34;;7629:39;;7684:9;7679:433;7703:6;:13;7699:1;:17;7679:433;;;7949:12;7971:26;:10;7995:1;7971:23;:26::i;:::-;7949:49;;8024:5;8012:6;8019:1;8012:9;;;;;;;;-1:-1:-1;;;;;8012:17:34;;;:9;;;;;;;;;;:17;;;;8057:37;;;;:29;:37;;;;;;:44;;;;;;;;;;;8043:11;;:8;;8052:1;;8043:11;;;;;;;;;;;;;;;:58;-1:-1:-1;7718:3:34;;7679:433;;;;7319:799;;;;:::o;7385:700:33:-;7544:53;7600:29;;;:21;:29;;;;;7479:22;;;;7661:21;7600:29;7661:19;:21::i;:::-;7648:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7648:35:33;;7639:44;;7718:6;:13;7704:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7704:28:33;;7693:39;;7748:9;7743:336;7767:6;:13;7763:1;:17;7743:336;;;8040:28;:12;8066:1;8040:25;:28::i;:::-;8014:6;8021:1;8014:9;;;;;;;;;;;;;8025:8;8034:1;8025:11;;;;;;;;;;;;;;;;;8013:55;;;;-1:-1:-1;;;;;8013:55:33;;;;;7782:3;;7743:336;;3313:295:32;3368:7;3585:16;3593:7;3585;:16::i;:::-;3569:13;3574:7;3569:4;:13::i;:::-;:32;;3313:295;-1:-1:-1;;3313:295:32:o;1495:105:11:-;1553:7;1584:1;1579;:6;;:14;;1592:1;1579:14;;;-1:-1:-1;1588:1:11;;1495:105;-1:-1:-1;1495:105:11:o;1683:104::-;1741:7;1771:1;1767;:5;:13;;1779:1;1767:13;;8311:267:29;-1:-1:-1;;;;;8461:30:29;;;;;;;:21;:30;;;;;;;;:37;;;;;;;;;;;;;;:50;;;8526:45;;;;;8565:5;;8526:45;:::i;2311:1170:7:-;2389:4;2405:16;2424:11;:9;:11::i;:::-;2405:30;;2613:15;2602:8;:26;2598:69;;;2651:5;2644:12;;;;;2598:69;2677:16;2696:11;:9;:11::i;:::-;2677:30;-1:-1:-1;2721:22:7;2717:175;;2876:5;2869:12;;;;;;2717:175;3014:18;3056:8;3076:11;:9;:11::i;:::-;3066:22;;;;;;;3045:73;;;;;3090:10;;3102:5;;3109:8;;3045:73;;:::i;:::-;;;;;;;;;;;;;3035:84;;;;;;3014:105;;3129:14;3146:28;3163:10;3146:16;:28::i;:::-;3129:45;;3185:7;3194:9;3205;3218:12;:10;:12::i;:::-;3184:46;;;;;;3241:24;3268:26;3278:6;3286:1;3289;3292;3268:26;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3268:26:7;;-1:-1:-1;;3268:26:7;;;-1:-1:-1;;;;;;;3416:30:7;;;;;;:58;;;3470:4;-1:-1:-1;;;;;3450:24:7;:16;-1:-1:-1;;;;;3450:24:7;;3416:58;3409:65;2311:1170;-1:-1:-1;;;;;;;;;;;2311:1170:7:o;15728:1047:28:-;15978:25;16017:26;16057:24;16106:20;16129:22;:14;:20;:22::i;:::-;16106:45;;16161:21;16185:23;:15;:21;:23::i;:::-;16161:47;;16244:77;16253:32;:14;:30;:32::i;:::-;16287:33;:15;:31;:33::i;16244:77::-;16218:23;;;:103;16472:49;;;;;-1:-1:-1;;;;;16472:11:28;;;;;:49;;16218:7;;16493:12;;16507:13;;16472:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16453:68;;16532:16;16550:17;16571:59;16583:7;:12;;;16597:7;:14;;;16613:16;16571:11;:59::i;:::-;16531:99;;-1:-1:-1;16531:99:28;-1:-1:-1;16661:37:28;:14;16531:99;16661:27;:37::i;:::-;16641:57;-1:-1:-1;16729:39:28;:15;16758:9;16729:28;:39::i;:::-;16708:60;;15728:1047;;;;;;;;;;;;:::o;12976:506:32:-;13067:7;13282:25;13317:72;13326:30;13342:13;13326:15;:30::i;:::-;13358;13374:13;13358:15;:30::i;13317:72::-;13282:108;;13408:67;13414:19;13419:13;13414:4;:19::i;:::-;13435;13440:13;13435:4;:19::i;:::-;13456:18;13408:67;;:5;:67::i;8138:144:14:-;-1:-1:-1;;;;;8258:17:14;8232:7;8258:17;;;:12;;;;;:17;;;;;;;8138:144::o;5993:115::-;6090:11;;5993:115::o;7365:156::-;7462:7;7488:19;;;:12;;;;:19;;;;;:26;;;7365:156::o;7291:321:32:-;7369:7;7388:15;7406:25;7424:6;7406:13;7411:7;7406:4;:13::i;:::-;:17;;:25::i;:::-;7388:43;;7441:22;7466:16;7474:7;7466;:16::i;:::-;7441:41;-1:-1:-1;7521:12:32;7551:54;7561:7;7441:41;7521:12;7551:9;:54::i;7881:321::-;7959:7;7978:15;7996:25;8014:6;7996:13;8001:7;7996:4;:13::i;:::-;:17;;:25::i;3729:177:14:-;3865:19;;;;:12;;;;:19;;;;;;:26;;;:34;3729:177::o;16201:169:35:-;16277:6;16285;16319;-1:-1:-1;;;;;16310:15:35;:6;-1:-1:-1;;;;;16310:15:35;;:53;;16348:6;16356;16310:53;;;16329:6;16337;16310:53;16303:60;;;;16201:169;;;;;:::o;15928:158::-;16010:7;16063:6;16071;16046:32;;;;;;;;;:::i;:::-;;;;;;;;;;;;;16036:43;;;;;;16029:50;;15928:158;;;;:::o;11934:395:32:-;12030:7;12223:99;12233:27;12249:10;12233:15;:27::i;:::-;12262:30;12278:13;12262:15;:30::i;:::-;12294:27;12310:10;12294:15;:27::i;:::-;12223:9;:99::i;12458:395::-;12554:7;12747:99;12757:27;12773:10;12757:15;:27::i;:::-;12786:30;12802:13;12786:15;:30::i;7708:278:14:-;-1:-1:-1;;;;;7872:17:14;;7837:7;7872:17;;;:12;;;:17;;;;;;7899:30;7908:9;;;7919;7899:8;:30::i;:::-;7946:33;7964:3;7977:1;7969:5;:9;7946:17;:33::i;:::-;7939:40;7708:278;-1:-1:-1;;;;;7708:278:14:o;1673:146:22:-;1737:7;1763:26;:24;:26::i;:::-;-1:-1:-1;;;;;1763:47:22;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;992:182:6:-;1111:56;1125:1;1120;:6;:16;;;;;1135:1;1130;:6;1120:16;5002:3:2;1111:8:6;:56::i;10568:1072:24:-;10822:30;10894:8;:15;10880:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;10880:30:24;;10864:46;;10925:9;10920:714;10944:13;;:20;10940:24;;10920:714;;;10985:17;11005:10;11016:1;11005:13;;;;;;;;;;;;;;10985:33;;11032:62;11054:6;:13;;;11068:1;11054:16;;;;;;;;;;;;;;11041:9;:29;;8263:3:2;11032:8:24;:62::i;:::-;11184:12;11199:6;:13;;;11213:1;11199:16;;;;;;;;;;;;;;11184:31;;11229:66;11240:5;11247:9;11258;11269:6;:25;;;11229:10;:66::i;:::-;11310:17;11330:21;11352:1;11330:24;;;;;;;;;;;;;;11310:44;;11368:51;11382:25;11401:5;11382:18;:25::i;:::-;11409:9;11368:13;:51::i;:::-;11573:50;11598:24;:9;11612;11598:13;:24::i;:::-;11573:8;11582:1;11573:11;;;;;;;;;;;;;;:24;;:50;;;;:::i;:::-;11554:13;11568:1;11554:16;;;;;;;;;;;;;:69;;;;;10920:714;;;10966:3;;;;;10920:714;;;;10568:1072;;;;;;;:::o;8626:1605::-;8868:30;9020:18;9083:8;:15;9069:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;9069:30:24;;9053:46;;9114:9;9109:1028;9133:13;;:20;9129:24;;9109:1028;;;9174:16;9193:9;9203:1;9193:12;;;;;;;;;;;;;;9174:31;;9219:61;9240:6;:13;;;9254:1;9240:16;;;;;;;;;;;;;;9228:8;:28;;8315:3:2;9219:8:24;:61::i;:::-;9375:12;9390:6;:13;;;9404:1;9390:16;;;;;;;;;;;;;;9375:31;;9420:65;9434:5;9441:8;9451:6;9459;:25;;;9420:13;:65::i;:::-;9504:13;9511:5;9504:6;:13::i;:::-;9500:89;;;9550:24;:10;9565:8;9550:14;:24::i;:::-;9537:37;;9500:89;9603:17;9623:21;9645:1;9623:24;;;;;;;;;;;;;;9603:44;;9661:51;9675:25;9694:5;9675:18;:25::i;9661:51::-;9946:9;9934:8;:21;;9933:193;;10080:46;10117:8;10105:9;:20;10080:8;10089:1;10080:11;;;;;;;:46;9933:193;;;10015:46;10051:9;10040:8;:20;10015:8;10024:1;10015:11;;;;;;;;;;;;;;:24;;:46;;;;:::i;:::-;9914:13;9928:1;9914:16;;;;;;;;;;;;;:212;;;;;9109:1028;;;9155:3;;;;;9109:1028;;;;10193:31;10213:10;10193:19;:31::i;5766:137:14:-;-1:-1:-1;;;;;5874:17:14;5851:4;5874:17;;;:12;;;;;:17;;;;;;:22;;;5766:137::o;6714:226:35:-;6845:88;6878:6;6886:5;6893:31;6926:6;6845:32;:88::i;4741:234:34:-;4879:89;4913:6;4921:5;4928:31;4961:6;4879:33;:89::i;4873:218:33:-;5003:81;5029:6;5037:5;5044:31;5077:6;5003:25;:81::i;7218:226:35:-;7349:88;7382:6;7390:5;7397:31;7430:6;7349:32;:88::i;5269:234:34:-;5407:89;5441:6;5449:5;5456:31;5489:6;5407:33;:89::i;5365:218:33:-;5495:81;5521:6;5529:5;5536:31;5569:6;5495:25;:81::i;7775:251:35:-;7909:6;7934:85;7967:6;7975:5;7982:28;8012:6;7934:32;:85::i;5850:259:34:-;5991:6;6016:86;6050:6;6058:5;6065:28;6095:6;6016:33;:86::i;5910:243:33:-;6043:6;6068:78;6094:6;6102:5;6109:28;6139:6;6068:25;:78::i;5175:135:15:-;5259:7;5285:3;:11;;5297:5;5285:18;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;5285:18:15;;5175:135;-1:-1:-1;;;5175:135:15:o;6981:228:14:-;7073:6;7140:19;;;:12;;;;:19;;;;;7177:10;;7189:12;;;-1:-1:-1;;;;;7177:10:14;;;;6981:228::o;4100:202:7:-;4144:7;4267:27;4292:1;4267:24;:27::i;6074:1492:31:-;6127:12;6712:1;6699:15;6694:3;6690:25;6910:8;6940:10;6935:79;;;;7036:10;7031:79;;;;7132:10;7127:79;;;;7228:10;7223:85;;;;7330:10;7325:86;;;;7466:66;7458:74;;6903:647;;6935:79;6981:15;6973:23;;6935:79;;7031;7077:15;7069:23;;7031:79;;7127;7173:15;7165:23;;7127:79;;7223:85;7269:21;7261:29;;7223:85;;7325:86;7371:22;7363:30;;6903:647;;;6405:1155;:::o;5154:500:7:-;5198:19;5238:8;;5229:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5346:13:7;;5229:17;;-1:-1:-1;;;1518:6:7;-1:-1:-1;5342:306:7;;;5600:22;5584:14;5580:43;5572:6;5565:59;5154:500;:::o;3199:183:13:-;3276:7;3341:20;:18;:20::i;:::-;3363:10;3312:62;;;;;;;;;:::i;4578:385:7:-;4660:7;4681:9;4704;4836:30;4861:4;4836:24;:30::i;:::-;4828:39;-1:-1:-1;4882:30:7;4907:4;4882:24;:30::i;:::-;4878:34;;4926:30;4951:4;4926:24;:30::i;14005:259:32:-;14205:3;14185:23;14232:3;14213:22;;;;14184:52;:72;;14005:259::o;6377:650::-;6504:7;6540:16;;;6789:75;6798:15;;;;;;:34;;;6826:6;6817;:15;6798:34;9492:3:2;6789:8:32;:75::i;:::-;6984:36;6990:5;6997:8;7007:12;6984:5;:36::i;948:166:11:-;1006:7;1025:37;1039:1;1034;:6;;4370:1:2;1025:8:11;:37::i;:::-;-1:-1:-1;1084:5:11;;;948:166::o;8366:346:32:-;8445:7;8464:15;8482:25;8500:6;8482:13;8487:7;8482:4;:13::i;:25::-;8464:43;;8517:18;8538:28;8559:6;8538:16;8546:7;8538;:16::i;:28::-;8517:49;;8576:30;8609:24;8625:7;8609:15;:24::i;:::-;8576:57;;8651:54;8661:7;8670:10;8682:22;8651:9;:54::i;8435:1028:35:-;8633:6;8665:37;8716:13;8743:16;8787;8816:32;8841:6;8816:24;:32::i;:::-;8651:197;;;;;;;;;8859:12;8894:6;-1:-1:-1;;;;;8885:15:35;:5;-1:-1:-1;;;;;8885:15:35;;8881:382;;;8916:18;8937:26;8946:8;8956:6;8937:8;:26;;:::i;:::-;8916:47;-1:-1:-1;8985:33:35;8916:47;9009:8;8985:23;:33::i;:::-;9043:10;;-1:-1:-1;8977:41:35;-1:-1:-1;8881:382:35;;;9115:18;9136:26;9145:8;9155:6;9136:8;:26;;:::i;:::-;9115:47;-1:-1:-1;9184:33:35;9115:47;9208:8;9184:23;:33::i;:::-;9242:10;;-1:-1:-1;9176:41:35;-1:-1:-1;8881:382:35;9295:50;9326:8;9336;9295:30;:50::i;:::-;9273:72;;9380:53;9414:8;9424;9380:33;:53::i;:::-;9355:22;;;;:78;;;;-1:-1:-1;9451:5:35;;-1:-1:-1;;;8435:1028:35;;;;;;:::o;6534:483:34:-;6734:6;6752:22;6777:45;6808:6;6816:5;6777:30;:45::i;:::-;6752:70;;6833:18;6854:32;6863:14;6879:6;6854:8;:32;;:::i;:::-;6896:37;;;;:29;:37;;;;;;;;-1:-1:-1;;;;;6896:44:34;;;;;;;;;:57;;;6833:53;-1:-1:-1;6971:39:34;6833:53;6995:14;6971:23;:39::i;:::-;6964:46;6534:483;-1:-1:-1;;;;;;;6534:483:34:o;6558:545:33:-;6749:6;6823:29;;;:21;:29;;;;;6749:6;6887:43;6823:29;6924:5;6887:22;:43::i;:::-;6862:68;;6941:18;6962:32;6971:14;6987:6;6962:8;:32;;:::i;:::-;6941:53;-1:-1:-1;7004:35:33;:12;7021:5;6941:53;7004:16;:35::i;:::-;-1:-1:-1;7057:39:33;:10;7081:14;7057:23;:39::i;:::-;7050:46;6558:545;-1:-1:-1;;;;;;;;6558:545:33:o;8875:346:32:-;8954:7;8973:15;8991:25;9009:6;8991:13;8996:7;8991:4;:13::i;:25::-;8973:43;;9026:18;9047:28;9068:6;9047:16;9055:7;9047;:16::i;9569:263::-;9649:7;9668:19;9690:13;9695:7;9690:4;:13::i;:::-;9668:35;-1:-1:-1;9742:12:32;9771:54;9668:35;9794:10;9742:12;9771:9;:54::i;5873:273:7:-;6081:14;6073:56;-1:-1:-1;;6073:56:7;6060:70;;6036:104::o;4461:279:32:-;4546:6;4713:19;4721:10;4713:7;:19::i;:::-;4683;4691:10;4683:7;:19::i;:::-;4676:57;;4461:279;-1:-1:-1;;;4461:279:32:o;13608:281::-;13702:7;13826:56;13832:22;13840:13;13832:7;:22::i;:::-;13856;13864:13;13856:7;:22::i;:::-;13880:1;13826:5;:56::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130::-;72:20;;97:33;72:20;97:33;:::i;1054:755::-;;1187:3;1180:4;1172:6;1168:17;1164:27;1154:2;;-1:-1;;1195:12;1154:2;1242:6;1229:20;1264:96;1279:80;1352:6;1279:80;:::i;:::-;1264:96;:::i;:::-;1388:21;;;1255:105;-1:-1;1432:4;1445:14;;;;1420:17;;;1534;;;1525:27;;;;1522:36;-1:-1;1519:2;;;1571:1;;1561:12;1519:2;1596:1;1581:222;1606:6;1603:1;1600:13;1581:222;;;8414:6;8401:20;8426:49;8469:5;8426:49;:::i;:::-;1674:66;;1754:14;;;;1782;;;;1628:1;1621:9;1581:222;;;1585:14;;;;;1147:662;;;;:::o;3370:774::-;;3519:3;3512:4;3504:6;3500:17;3496:27;3486:2;;-1:-1;;3527:12;3486:2;3574:6;3561:20;3596:112;3611:96;3700:6;3611:96;:::i;3596:112::-;3736:21;;;3587:121;-1:-1;3780:4;3793:14;;;;3768:17;;;3888:1;3873:265;3898:6;3895:1;3892:13;3873:265;;;3981:3;3968:17;3772:6;3956:30;10034:4;;10013:19;;3956:30;10017:3;10013:19;;10009:30;10006:2;;;3888:1;;10042:12;10006:2;10070:20;10034:4;10070:20;:::i;:::-;3780:4;3956:30;;7664:20;10156:16;10149:75;10347:22;;3956:30;10347:22;17281:20;3780:4;10312:5;10308:16;10301:75;10500:22;;3956:30;10500:22;17281:20;10347:22;10465:5;10461:16;10454:75;10646:22;;;;3956:30;10646:22;17281:20;10500:22;10611:5;10607:16;10600:75;;10034:4;3956:30;10753:19;10740:33;10726:47;;10793:18;10785:6;10782:30;10779:2;;;3888:1;;10815:12;10779:2;10860:58;10914:3;3780:4;10905:6;3956:30;10890:22;;10860:58;:::i;:::-;10842:16;;;10835:84;3993:82;;-1:-1;;4089:14;;;;4117;;;;3920:1;3913:9;3873:265;;5868:707;;5985:3;5978:4;5970:6;5966:17;5962:27;5952:2;;-1:-1;;5993:12;5952:2;6040:6;6027:20;6062:80;6077:64;6134:6;6077:64;:::i;6062:80::-;6170:21;;;6053:89;-1:-1;6214:4;6227:14;;;;6202:17;;;6316;;;6307:27;;;;6304:36;-1:-1;6301:2;;;6353:1;;6343:12;6301:2;6378:1;6363:206;6388:6;6385:1;6382:13;6363:206;;;17281:20;;6456:50;;6520:14;;;;6548;;;;6410:1;6403:9;6363:206;;6601:722;;6729:3;6722:4;6714:6;6710:17;6706:27;6696:2;;-1:-1;;6737:12;6696:2;6777:6;6771:13;6799:80;6814:64;6871:6;6814:64;:::i;6799:80::-;6907:21;;;6790:89;-1:-1;6951:4;6964:14;;;;6939:17;;;7053;;;7044:27;;;;7041:36;-1:-1;7038:2;;;7090:1;;7080:12;7038:2;7115:1;7100:217;7125:6;7122:1;7119:13;7100:217;;;17429:13;;7193:61;;7268:14;;;;7296;;;;7147:1;7140:9;7100:217;;7331:124;7395:20;;7420:30;7395:20;7420:30;:::i;7870:440::-;;7971:3;7964:4;7956:6;7952:17;7948:27;7938:2;;-1:-1;;7979:12;7938:2;8026:6;8013:20;61214:18;61206:6;61203:30;61200:2;;;-1:-1;;61236:12;61200:2;8048:64;10013:19;61290:17;;-1:-1;;61286:33;61377:4;61367:15;8048:64;:::i;:::-;8039:73;;8132:6;8125:5;8118:21;8236:3;61377:4;8227:6;8160;8218:16;;8215:25;8212:2;;;8253:1;;8243:12;8212:2;68088:6;61377:4;8160:6;8156:17;61377:4;8194:5;8190:16;68065:30;68144:1;68126:16;;;61377:4;68126:16;68119:27;8194:5;7931:379;-1:-1;;7931:379::o;9028:176::-;9118:20;;9143:56;9118:20;9143:56;:::i;9396:158::-;9477:20;;70855:1;70845:12;;70835:2;;70871:1;;70861:12;9561:176;9651:20;;70979:1;70969:12;;70959:2;;70995:1;;70985:12;10983:1122;;11106:4;11094:9;11089:3;11085:19;11081:30;11078:2;;;-1:-1;;11114:12;11078:2;11142:20;11106:4;11142:20;:::i;:::-;11133:29;;11227:17;11214:31;11265:18;;11257:6;11254:30;11251:2;;;11242:1;;11287:12;11251:2;11332:90;11418:3;11409:6;11398:9;11394:22;11332:90;:::i;:::-;11314:16;11307:116;11521:2;11510:9;11506:18;11493:32;11479:46;;11265:18;11537:6;11534:30;11531:2;;;11242:1;;11567:12;11531:2;11612:74;11682:3;11673:6;11662:9;11658:22;11612:74;:::i;:::-;11521:2;11598:5;11594:16;11587:100;11780:2;11769:9;11765:18;11752:32;11738:46;;11265:18;11796:6;11793:30;11790:2;;;11242:1;;11826:12;11790:2;;11871:58;11925:3;11916:6;11905:9;11901:22;11871:58;:::i;:::-;11780:2;11857:5;11853:16;11846:84;;12037:46;12079:3;12004:2;12059:9;12055:22;12037:46;:::i;:::-;12004:2;12023:5;12019:16;12012:72;11072:1033;;;;:::o;12147:800::-;;12269:4;12257:9;12252:3;12248:19;12244:30;12241:2;;;-1:-1;;12277:12;12241:2;12305:20;12269:4;12305:20;:::i;:::-;12296:29;;85:6;72:20;97:33;124:5;97:33;:::i;:::-;12384:75;;12535:2;12586:22;;7395:20;7420:30;7395:20;7420:30;:::i;:::-;12535:2;12550:16;;12543:72;12681:2;12743:22;;217:20;242:41;217:20;242:41;:::i;:::-;12681:2;12696:16;;12689:83;12846:2;12897:22;;7395:20;7420:30;7395:20;7420:30;:::i;17492:241::-;;17596:2;17584:9;17575:7;17571:23;17567:32;17564:2;;;-1:-1;;17602:12;17564:2;85:6;72:20;97:33;124:5;97:33;:::i;17740:366::-;;;17861:2;17849:9;17840:7;17836:23;17832:32;17829:2;;;-1:-1;;17867:12;17829:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;17919:63;-1:-1;18019:2;18058:22;;72:20;97:33;72:20;97:33;:::i;:::-;18027:63;;;;17823:283;;;;;:::o;18113:485::-;;;;18248:2;18236:9;18227:7;18223:23;18219:32;18216:2;;;-1:-1;;18254:12;18216:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;18306:63;-1:-1;18406:2;18445:22;;72:20;97:33;72:20;97:33;:::i;:::-;18414:63;-1:-1;18514:2;18550:22;;7395:20;7420:30;7395:20;7420:30;:::i;:::-;18522:60;;;;18210:388;;;;;:::o;18605:532::-;;;18766:2;18754:9;18745:7;18741:23;18737:32;18734:2;;;-1:-1;;18772:12;18734:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;18824:63;-1:-1;18952:2;18937:18;;18924:32;18976:18;18965:30;;18962:2;;;-1:-1;;18998:12;18962:2;19028:93;19113:7;19104:6;19093:9;19089:22;19028:93;:::i;:::-;19018:103;;;18728:409;;;;;:::o;19144:441::-;;19305:2;;19293:9;19284:7;19280:23;19276:32;19273:2;;;-1:-1;;19311:12;19273:2;19369:17;19356:31;19407:18;19399:6;19396:30;19393:2;;;-1:-1;;19429:12;19393:2;19537:22;;4332:4;4320:17;;4316:27;-1:-1;4306:2;;-1:-1;;4347:12;4306:2;4394:6;4381:20;4416:112;4431:96;4520:6;4431:96;:::i;4416:112::-;4556:21;;;4613:14;;;;4588:17;;;4714:4;4702:17;;;4693:27;;;;4690:36;-1:-1;4687:2;;;-1:-1;;4729:12;4687:2;-1:-1;4755:10;;4749:238;4774:6;4771:1;4768:13;4749:238;;;4714:4;14263:9;14258:3;14254:19;14250:30;14247:2;;;-1:-1;;14283:12;14247:2;14311:20;4714:4;14311:20;:::i;:::-;14413:72;14481:3;14457:22;14413:72;:::i;:::-;14395:16;14388:98;19305:2;14607:9;14603:22;7664:20;19305:2;14568:5;14564:16;14557:75;14694:2;14727:64;14787:3;14694:2;14767:9;14763:22;14727:64;:::i;:::-;14709:16;;;14702:90;14855:2;14909:22;;;17281:20;14870:16;;;14863:75;4842:82;;4796:1;4789:9;;;;;4938:14;;;;4966;;;;4749:238;;;-1:-1;19449:120;;19267:318;-1:-1;;;;;;;;19267:318::o;19592:441::-;;19753:2;;19741:9;19732:7;19728:23;19724:32;19721:2;;;-1:-1;;19759:12;19721:2;19817:17;19804:31;19855:18;19847:6;19844:30;19841:2;;;-1:-1;;19877:12;19841:2;19985:22;;5181:4;5169:17;;5165:27;-1:-1;5155:2;;-1:-1;;5196:12;5155:2;5243:6;5230:20;5265:112;5280:96;5369:6;5280:96;:::i;5265:112::-;5405:21;;;5462:14;;;;5437:17;;;5563:4;5551:17;;;5542:27;;;;5539:36;-1:-1;5536:2;;;-1:-1;;5578:12;5536:2;-1:-1;5604:10;;5598:238;5623:6;5620:1;5617:13;5598:238;;;5563:4;16352:9;16347:3;16343:19;16339:30;16336:2;;;-1:-1;;16372:12;16336:2;16400:20;5563:4;16400:20;:::i;:::-;16502:72;16570:3;16546:22;16502:72;:::i;:::-;16484:16;16477:98;16670:65;16731:3;19753:2;16711:9;16707:22;16670:65;:::i;:::-;16652:16;;;16645:91;16799:2;16853:22;;;17281:20;16814:16;;;16807:75;16945:2;16978:49;17023:3;16999:22;;;16978:49;:::i;:::-;16960:16;;;16953:75;17094:3;17128:57;17181:3;17157:22;;;17128:57;:::i;:::-;17110:16;;;17103:83;5691:82;;5645:1;5638:9;;;;;5787:14;;;;5815;;;;5598:238;;20040:657;;;20222:2;20210:9;20201:7;20197:23;20193:32;20190:2;;;-1:-1;;20228:12;20190:2;20279:17;20273:24;20317:18;;20309:6;20306:30;20303:2;;;-1:-1;;20339:12;20303:2;20369:89;20450:7;20441:6;20430:9;20426:22;20369:89;:::i;:::-;20359:99;;20516:2;20505:9;20501:18;20495:25;20481:39;;20317:18;20532:6;20529:30;20526:2;;;-1:-1;;20562:12;20526:2;;20592:89;20673:7;20664:6;20653:9;20649:22;20592:89;:::i;20704:235::-;;20805:2;20793:9;20784:7;20780:23;20776:32;20773:2;;;-1:-1;;20811:12;20773:2;7408:6;7395:20;7420:30;7444:5;7420:30;:::i;20946:257::-;;21058:2;21046:9;21037:7;21033:23;21029:32;21026:2;;;-1:-1;;21064:12;21026:2;7543:6;7537:13;7555:30;7579:5;7555:30;:::i;21210:241::-;;21314:2;21302:9;21293:7;21289:23;21285:32;21282:2;;;-1:-1;;21320:12;21282:2;-1:-1;7664:20;;21276:175;-1:-1;21276:175::o;21458:787::-;;;;;21655:3;21643:9;21634:7;21630:23;21626:33;21623:2;;;-1:-1;;21662:12;21623:2;7677:6;7664:20;21714:63;;21814:2;21857:9;21853:22;72:20;97:33;124:5;97:33;:::i;:::-;21822:63;-1:-1;21922:2;21969:22;;217:20;242:41;217:20;242:41;:::i;:::-;21930:71;-1:-1;22066:2;22051:18;;22038:32;22090:18;22079:30;;22076:2;;;-1:-1;;22112:12;22076:2;22142:87;22221:7;22212:6;22201:9;22197:22;22142:87;:::i;:::-;22132:97;;;21617:628;;;;;;;:::o;23030:532::-;;;23191:2;23179:9;23170:7;23166:23;23162:32;23159:2;;;-1:-1;;23197:12;23159:2;7677:6;7664:20;23249:63;;23377:2;23366:9;23362:18;23349:32;23401:18;23393:6;23390:30;23387:2;;;-1:-1;;23423:12;23569:793;;;;23772:2;23760:9;23751:7;23747:23;23743:32;23740:2;;;-1:-1;;23778:12;23740:2;7677:6;7664:20;23830:63;;23958:2;;23947:9;23943:18;23930:32;23982:18;;23974:6;23971:30;23968:2;;;-1:-1;;24004:12;23968:2;24034:93;24119:7;24110:6;24099:9;24095:22;24034:93;:::i;:::-;24024:103;;24192:2;24181:9;24177:18;24164:32;24150:46;;23982:18;24208:6;24205:30;24202:2;;;-1:-1;;24238:12;24202:2;-1:-1;24314:22;;423:4;411:17;;407:27;-1:-1;397:2;;-1:-1;;438:12;397:2;485:6;472:20;507:80;522:64;579:6;522:64;:::i;507:80::-;615:21;;;672:14;;;;647:17;;;761;;;752:27;;;;749:36;-1:-1;746:2;;;-1:-1;;788:12;746:2;-1:-1;814:10;;808:206;833:6;830:1;827:13;808:206;;;85:6;72:20;97:33;124:5;97:33;:::i;:::-;901:50;;855:1;848:9;;;;;965:14;;;;993;;808:206;;;812:14;24258:88;;;;;;;;23734:628;;;;;:::o;24369:396::-;;;24505:2;24493:9;24484:7;24480:23;24476:32;24473:2;;;-1:-1;;24511:12;24473:2;7677:6;7664:20;24563:63;;24663:2;24721:9;24717:22;8748:20;8773:48;8815:5;8773:48;:::i;24772:239::-;;24875:2;24863:9;24854:7;24850:23;24846:32;24843:2;;;-1:-1;;24881:12;24843:2;7813:6;7800:20;-1:-1;;;;;;69828:5;64872:78;69804:5;69801:34;69791:2;;-1:-1;;69839:12;25308:1081;;;;;25566:3;25554:9;25545:7;25541:23;25537:33;25534:2;;;-1:-1;;25573:12;25534:2;8942:6;8929:20;8954:62;9010:5;8954:62;:::i;:::-;25625:92;-1:-1;25782:2;25767:18;;25754:32;25806:18;25795:30;;;25792:2;;;-1:-1;;25828:12;25792:2;25858:93;25943:7;25934:6;25923:9;25919:22;25858:93;:::i;:::-;25848:103;;26016:2;26005:9;26001:18;25988:32;25974:46;;25806:18;26032:6;26029:30;26026:2;;;-1:-1;;26062:12;26026:2;26092:78;26162:7;26153:6;26142:9;26138:22;26092:78;:::i;:::-;26082:88;;26235:2;26224:9;26220:18;26207:32;26193:46;;25806:18;26251:6;26248:30;26245:2;;;-1:-1;;26281:12;26245:2;;26311:62;26365:7;26356:6;26345:9;26341:22;26311:62;:::i;26396:289::-;;26524:2;26512:9;26503:7;26499:23;26495:32;26492:2;;;-1:-1;;26530:12;26492:2;9131:6;9118:20;9143:56;9193:5;9143:56;:::i;26692:1079::-;;;;;26992:3;26980:9;26971:7;26967:23;26963:33;26960:2;;;-1:-1;;26999:12;26960:2;27061:67;27120:7;27096:22;27061:67;:::i;:::-;27051:77;;27193:2;27182:9;27178:18;27165:32;27217:18;;27209:6;27206:30;27203:2;;;-1:-1;;27239:12;27203:2;27269:110;27371:7;27362:6;27351:9;27347:22;27269:110;:::i;:::-;27259:120;;27444:2;27433:9;27429:18;27416:32;27402:46;;27217:18;27460:6;27457:30;27454:2;;;-1:-1;;27490:12;27454:2;;27520:94;27606:7;27597:6;27586:9;27582:22;27520:94;:::i;:::-;27510:104;;;27669:86;27747:7;27651:2;27727:9;27723:22;27669:86;:::i;:::-;27659:96;;26954:817;;;;;;;:::o;27778:1465::-;;;;;;;28136:3;28124:9;28115:7;28111:23;28107:33;28104:2;;;-1:-1;;28143:12;28104:2;28205:67;28264:7;28240:22;28205:67;:::i;:::-;28195:77;;28337:2;;28326:9;28322:18;28309:32;28361:18;;28353:6;28350:30;28347:2;;;-1:-1;;28383:12;28347:2;28413:110;28515:7;28506:6;28495:9;28491:22;28413:110;:::i;:::-;28403:120;;28588:2;28577:9;28573:18;28560:32;28546:46;;28361:18;28604:6;28601:30;28598:2;;;-1:-1;;28634:12;28598:2;28664:94;28750:7;28741:6;28730:9;28726:22;28664:94;:::i;:::-;28654:104;;28813:86;28891:7;28795:2;28871:9;28867:22;28813:86;:::i;:::-;28803:96;;28964:3;28953:9;28949:19;28936:33;28922:47;;28361:18;28981:6;28978:30;28975:2;;;-1:-1;;29011:12;28975:2;-1:-1;29086:22;;2729:4;2717:17;;2713:27;-1:-1;2703:2;;-1:-1;;2744:12;2703:2;2791:6;2778:20;2813:79;2828:63;2884:6;2828:63;:::i;2813:79::-;2920:21;;;2977:14;;;;2952:17;;;3066;;;3057:27;;;;3054:36;-1:-1;3051:2;;;-1:-1;;3093:12;3051:2;-1:-1;3119:10;;3113:205;3138:6;3135:1;3132:13;3113:205;;;9810:20;;3206:49;;3160:1;3153:9;;;;;3269:14;;;;3297;;3113:205;;;3117:14;29031:87;;;;;;;;29155:3;29199:9;29195:22;17281:20;29164:63;;28098:1145;;;;;;;;:::o;29250:829::-;;;;;29467:3;29455:9;29446:7;29442:23;29438:33;29435:2;;;-1:-1;;29474:12;29435:2;29532:17;29519:31;29570:18;;29562:6;29559:30;29556:2;;;-1:-1;;29592:12;29556:2;29672:22;;;;15115:4;15094:19;;;15090:30;15087:2;;;-1:-1;;15123:12;15087:2;15151:20;15115:4;15151:20;:::i;:::-;7677:6;7664:20;15237:16;15230:75;15399:63;15458:3;15366:2;15438:9;15434:22;15399:63;:::i;:::-;15366:2;15385:5;15381:16;15374:89;15527:2;15601:9;15597:22;8401:20;8426:49;8469:5;8426:49;:::i;:::-;15527:2;15542:16;;15535:91;15724:65;15785:3;15691:2;15761:22;;15724:65;:::i;:::-;15691:2;15710:5;15706:16;15699:91;15853:3;15912:9;15908:22;17281:20;15853:3;15873:5;15869:16;15862:75;16030:3;16019:9;16015:19;16002:33;29570:18;16047:6;16044:30;16041:2;;;-1:-1;;16077:12;16041:2;16122:58;16176:3;16167:6;16156:9;16152:22;16122:58;:::i;:::-;16030:3;16108:5;16104:16;16097:84;;29612:92;;;;;;29759:86;29837:7;15366:2;29817:9;29813:22;29759:86;:::i;:::-;29429:650;;29749:96;;-1:-1;;;;16030:3;29922:22;;17281:20;;15115:4;30031:22;17281:20;;29429:650::o;30086:263::-;;30201:2;30189:9;30180:7;30176:23;30172:32;30169:2;;;-1:-1;;30207:12;30169:2;-1:-1;17429:13;;30163:186;-1:-1;30163:186::o;31259:137::-;-1:-1;;;;;65877:54;31346:45;;31340:56::o;32401:765::-;;32624:5;62148:12;63368:6;63363:3;63356:19;63405:4;;63400:3;63396:14;32636:93;;63405:4;32815:5;61514:14;-1:-1;32854:290;32879:6;32876:1;32873:13;32854:290;;;32940:13;;-1:-1;;;;;65877:54;36753:71;;30722:14;;;;62852;;;;32901:1;32894:9;32854:290;;;-1:-1;33150:10;;32540:626;-1:-1;;;;;32540:626::o;33203:682::-;;33393:5;62148:12;63368:6;63363:3;63356:19;63405:4;;63400:3;63396:14;33405:92;;63405:4;33567:5;61514:14;-1:-1;33606:257;33631:6;33628:1;33625:13;33606:257;;;33692:13;;34794:37;;30900:14;;;;62852;;;;33653:1;33646:9;33606:257;;35618:323;;35750:5;62148:12;63368:6;63363:3;63356:19;35833:52;35878:6;63405:4;63400:3;63396:14;63405:4;35859:5;35855:16;35833:52;:::i;:::-;10013:19;68864:14;-1:-1;;68860:28;35897:39;;;;63405:4;35897:39;;35698:243;-1:-1;;35698:243::o;38888:1729::-;;39049:6;39123:16;39117:23;69208:1;69201:5;69198:12;69188:2;;69214:9;69188:2;67713:38;37804:3;37797:62;;39303:4;39296:5;39292:16;39286:23;39315:78;39303:4;39382:3;39378:14;39364:12;39315:78;:::i;:::-;;39476:4;39469:5;39465:16;39459:23;39488:78;39476:4;39555:3;39551:14;39537:12;39488:78;:::i;:::-;;39647:4;39640:5;39636:16;39630:23;39647:4;39711:3;39707:14;34794:37;39803:4;39796:5;39792:16;39786:23;39803:4;39867:3;39863:14;34794:37;39968:4;39961:5;39957:16;39951:23;39968:4;40032:3;40028:14;34794:37;40122:4;40115:5;40111:16;40105:23;40134:63;40122:4;40186:3;40182:14;40168:12;40134:63;:::i;:::-;;40274:4;40267:5;40263:16;40257:23;40286:63;40274:4;40338:3;40334:14;40320:12;40286:63;:::i;:::-;;40432:6;;40425:5;40421:18;40415:25;39049:6;40432;40464:3;40460:16;40453:40;40508:71;39049:6;39044:3;39040:16;40560:12;40508:71;:::i;40968:387::-;34794:37;;;-1:-1;;;;;;64872:78;41219:2;41210:12;;35209:56;41319:11;;;41110:245::o;41362:291::-;;68088:6;68083:3;68078;68065:30;68126:16;;68119:27;;;68126:16;41506:147;-1:-1;41506:147::o;41660:271::-;;36458:5;62148:12;36569:52;36614:6;36609:3;36602:4;36595:5;36591:16;36569:52;:::i;:::-;36633:16;;;;;41794:137;-1:-1;;41794:137::o;41938:452::-;-1:-1;;68975:2;68971:14;;;;;37093:86;;68971:14;;;;;42236:2;42227:12;;37093:86;42353:12;;;42112:278::o;42397:659::-;38391:66;38371:87;;38356:1;38477:11;;34794:37;;;;42908:12;;;34794:37;43019:12;;;42642:414::o;43449:222::-;-1:-1;;;;;65877:54;;;;31346:45;;43576:2;43561:18;;43547:124::o;43678:444::-;-1:-1;;;;;65877:54;;;31346:45;;65877:54;;;;44025:2;44010:18;;31346:45;44108:2;44093:18;;34794:37;;;;43861:2;43846:18;;43832:290::o;44129:377::-;-1:-1;;;;;65877:54;;31346:45;;44306:2;44291:18;;65527:57;65578:5;65527:57;:::i;:::-;67562:48;44492:2;44481:9;44477:18;37640:72;44277:229;;;;;:::o;44513:333::-;-1:-1;;;;;65877:54;;;;31346:45;;44832:2;44817:18;;34794:37;44668:2;44653:18;;44639:207::o;44853:400::-;;45045:2;45066:17;45059:47;45120:123;45045:2;45034:9;45030:18;45229:6;45120:123;:::i;45260:659::-;;45530:2;45551:17;45544:47;45605:123;45530:2;45519:9;45515:18;45714:6;45605:123;:::i;:::-;45766:20;;;45761:2;45746:18;;;45739:48;;;;62148:12;;63356:19;;;61514:14;;;;63396;;;-1:-1;32072:260;32097:6;32094:1;32091:13;32072:260;;;32158:13;;-1:-1;;;;;65877:54;31346:45;;62852:14;;;;30510;;;;32119:1;32112:9;32072:260;;;-1:-1;45793:116;;45501:418;-1:-1;;;;;;;45501:418::o;45926:914::-;;46272:2;46293:17;46286:47;46347:123;46272:2;46261:9;46257:18;46456:6;46347:123;:::i;:::-;46518:9;46512:4;46508:20;46503:2;46492:9;46488:18;46481:48;46543:106;46644:4;46635:6;46543:106;:::i;:::-;46535:114;;46697:9;46691:4;46687:20;46682:2;46671:9;46667:18;46660:48;46722:108;46825:4;46816:6;46722:108;:::i;46847:1114::-;;47241:3;47263:17;47256:47;47317:123;47241:3;47230:9;47226:19;47426:6;47317:123;:::i;:::-;47488:9;47482:4;47478:20;47473:2;47462:9;47458:18;47451:48;47513:108;47616:4;47607:6;47513:108;:::i;:::-;47505:116;;47669:9;47663:4;47659:20;47654:2;47643:9;47639:18;47632:48;47694:108;47797:4;47788:6;47694:108;:::i;:::-;47686:116;;47850:9;47844:4;47840:20;47835:2;47824:9;47820:18;47813:48;47875:76;47946:4;47937:6;47875:76;:::i;47968:770::-;;48266:2;48287:17;48280:47;48341:123;48266:2;48255:9;48251:18;48450:6;48341:123;:::i;:::-;48512:9;48506:4;48502:20;48497:2;48486:9;48482:18;48475:48;48537:108;48640:4;48631:6;48537:108;:::i;:::-;48529:116;;;34824:5;48724:2;48713:9;48709:18;34794:37;48237:501;;;;;;:::o;48745:366::-;;48920:2;48941:17;48934:47;48995:106;48920:2;48909:9;48905:18;49087:6;48995:106;:::i;49495:210::-;64706:13;;64699:21;34687:34;;49616:2;49601:18;;49587:118::o;49712:432::-;64706:13;;64699:21;34687:34;;50047:2;50032:18;;34794:37;;;;50130:2;50115:18;;34794:37;49889:2;49874:18;;49860:284::o;50151:222::-;34794:37;;;50278:2;50263:18;;50249:124::o;50380:444::-;34794:37;;;-1:-1;;;;;65877:54;;;50727:2;50712:18;;31346:45;65877:54;50810:2;50795:18;;31346:45;50563:2;50548:18;;50534:290::o;50831:1140::-;;34824:5;34801:3;34794:37;-1:-1;;;;;65888:42;64516:5;65877:54;51367:2;51356:9;51352:18;31346:45;65888:42;64516:5;65877:54;51458:2;51447:9;51443:18;31189:58;;51202:3;51495:2;51484:9;51480:18;51473:48;51535:108;51202:3;51191:9;51187:19;51629:6;51535:108;:::i;:::-;34824:5;51722:3;51711:9;51707:19;34794:37;34824:5;51806:3;51795:9;51791:19;34794:37;51860:9;51854:4;51850:20;51844:3;51833:9;51829:19;51822:49;51885:76;51956:4;51947:6;51885:76;:::i;:::-;51877:84;51173:798;-1:-1;;;;;;;;;;51173:798::o;51978:700::-;34794:37;;;52398:2;52383:18;;34794:37;;;;-1:-1;;;;;65877:54;;;;52497:2;52482:18;;31346:45;52580:2;52565:18;;34794:37;52663:3;52648:19;;34794:37;52233:3;52218:19;;52204:474::o;52685:668::-;34794:37;;;53089:2;53074:18;;34794:37;;;;53172:2;53157:18;;34794:37;;;;53255:2;53240:18;;34794:37;-1:-1;;;;;65877:54;53338:3;53323:19;;31346:45;52924:3;52909:19;;52895:458::o;53360:548::-;34794:37;;;66093:4;66082:16;;;;53728:2;53713:18;;40921:35;53811:2;53796:18;;34794:37;53894:2;53879:18;;34794:37;53567:3;53552:19;;53538:370::o;54734:266::-;54883:2;54868:18;;65527:57;65578:5;65527:57;:::i;:::-;37640:72;;;54854:146;:::o;55232:325::-;34794:37;;;55543:2;55528:18;;34794:37;55383:2;55368:18;;55354:203::o;55564:872::-;;55885:3;55907:17;55900:47;55961:118;55885:3;55874:9;55870:19;56065:6;55961:118;:::i;:::-;56127:9;56121:4;56117:20;56112:2;56101:9;56097:18;56090:48;56152:108;56255:4;56246:6;56152:108;:::i;:::-;56339:2;56324:18;;34794:37;;;;-1:-1;;56422:2;56407:18;34794:37;56144:116;55856:580;-1:-1;;55856:580::o;56443:612::-;;56686:2;56707:17;56700:47;56761:118;56686:2;56675:9;56671:18;56865:6;56761:118;:::i;:::-;56958:2;56943:18;;34794:37;;;;-1:-1;57041:2;57026:18;34794:37;56753:126;56657:398;-1:-1;56657:398::o;57631:556::-;34794:37;;;58007:2;57992:18;;34794:37;;;;58090:2;58075:18;;34794:37;-1:-1;;;;;65877:54;58173:2;58158:18;;31346:45;57842:3;57827:19;;57813:374::o;58194:256::-;58256:2;58250:9;58282:17;;;58357:18;58342:34;;58378:22;;;58339:62;58336:2;;;58414:1;;58404:12;58336:2;58256;58423:22;58234:216;;-1:-1;58234:216::o;58457:304::-;;58616:18;58608:6;58605:30;58602:2;;;-1:-1;;58638:12;58602:2;-1:-1;58683:4;58671:17;;;58736:15;;58539:222::o;68161:268::-;68226:1;68233:101;68247:6;68244:1;68241:13;68233:101;;;68314:11;;;68308:18;68295:11;;;68288:39;68269:2;68262:10;68233:101;;;68349:6;68346:1;68343:13;68340:2;;;-1:-1;;68226:1;68396:16;;68389:27;68210:219::o;69003:115::-;69096:1;69089:5;69086:12;69076:2;;69102:9;69237:117;-1:-1;;;;;69324:5;65877:54;69299:5;69296:35;69286:2;;69345:1;;69335:12;69501:111;69582:5;64706:13;64699:21;69560:5;69557:32;69547:2;;69603:1;;69593:12;70523:117;70615:1;70608:5;70605:12;70595:2;;70631:1;;70621:12

Swarm Source

ipfs://be72bdf8e7a3c38606c5f954fbe2d77798347aaa1cfb76fe77ec2f6c245d24bc
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Validator ID :
0 FTM

Amount Staked
0

Amount Delegated
0

Staking Total
0

Staking Start Epoch
0

Staking Start Time
0

Proof of Importance
0

Origination Score
0

Validation Score
0

Active
0

Online
0

Downtime
0 s
Address Amount claimed Rewards Created On Epoch Created On
Block Uncle Number Difficulty Gas Used Reward
Loading