ETH Price: $2,196.49 (-5.54%)

Transaction Decoder

Block:
12330125 at Apr-28-2021 04:56:27 PM +UTC
Transaction Fee:
0.005740032 ETH $12.61
Gas Used:
44,844 Gas / 128 Gwei

Emitted Events:

255 DelegateCallProxyManyToOne.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000023ab1dd0171ea56ad5631f1446ed147c23fa8860, 0x0000000000000000000000006c8102517a613774e1e5e46451cb29d4cffee34f, 0000000000000000000000000000000000000000000000001b8f6e18a056c884 )

Account State Difference:

  Address   Before After State Difference Code
0x23ab1dD0...c23FA8860
0.16617628620585479 Eth
Nonce: 1250
0.16043625420585479 Eth
Nonce: 1251
0.005740032
(BeePool)
1,308.124181732176904129 Eth1,308.129921764176904129 Eth0.005740032
0xd3dEFf00...684fa436C

Execution Trace

DelegateCallProxyManyToOne.a9059cbb( )
  • ManyToOneImplementationHolder.STATICCALL( )
  • SigmaIndexPoolV1.transfer( dst=0x6C8102517a613774e1E5e46451cb29D4CfFEe34f, amt=1985927012741990532 ) => ( True )
    File 1 of 3: DelegateCallProxyManyToOne
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /**
     * @dev Because we use the code hashes of the proxy contracts for proxy address
     * derivation, it is important that other packages have access to the correct
     * values when they import the salt library.
     */
    library CodeHashes {
      bytes32 internal constant ONE_TO_ONE_CODEHASH = 0x63d9f7b5931b69188c8f6b806606f25892f1bb17b7f7e966fe3a32c04493aee4;
      bytes32 internal constant MANY_TO_ONE_CODEHASH = 0xa035ad05a1663db5bfd455b99cd7c6ac6bd49269738458eda140e0b78ed53f79;
      bytes32 internal constant IMPLEMENTATION_HOLDER_CODEHASH = 0x11c370493a726a0ffa93d42b399ad046f1b5a543b6e72f1a64f1488dc1c58f2c;
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    /* ==========  External Libraries  ========== */
    import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
    import { Address } from "@openzeppelin/contracts/utils/Address.sol";
    import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
    /* ==========  Proxy Contracts  ========== */
    import "./ManyToOneImplementationHolder.sol";
    import { DelegateCallProxyManyToOne } from "./DelegateCallProxyManyToOne.sol";
    import { DelegateCallProxyOneToOne } from "./DelegateCallProxyOneToOne.sol";
    /* ==========  Internal Libraries  ========== */
    import { SaltyLib as Salty } from "./SaltyLib.sol";
    import { CodeHashes } from "./CodeHashes.sol";
    /* ==========  Inheritance  ========== */
    import "./interfaces/IDelegateCallProxyManager.sol";
    /**
     * @dev Contract that manages deployment and upgrades of delegatecall proxies.
     *
     * An implementation identifier can be created on the proxy manager which is
     * used to specify the logic address for a particular contract type, and to
     * upgrade the implementation as needed.
     *
     * ====== Proxy Types ======
     * A one-to-one proxy is a single proxy contract with an upgradeable implementation
     * address.
     *
     * A many-to-one proxy is a single upgradeable implementation address that may be
     * used by many proxy contracts.
     *
     * ====== Access Control ======
     * The proxy manager has a single address as its owner.
     *
     * The owner is the sole account with the following permissions:
     * - Create new many-to-one implementations
     * - Create new one-to-one proxies
     * - Modify the implementation address of existing proxies
     * - Lock proxies
     * - Designate approved deployers
     * - Remove approved deployers
     * - Modify the owner address
     *
     * Approved deployers may only deploy many-to-one proxies.
     *
     * ====== Upgrades ======
     * Proxies can be upgraded by the owner if they are not locked.
     *
     * Many-to-one proxy implementations are upgraded by calling the holder contract
     * for the implementation ID being upgraded.
     * One-to-one proxies are upgraded by calling the proxy contract directly.
     *
     * The owner can lock a one-to-one proxy or many-to-one implementation ID so that
     * it becomes impossible to upgrade.
     */
    contract DelegateCallProxyManager is Ownable, IDelegateCallProxyManager {
    /* ==========  Events  ========== */
      event DeploymentApprovalGranted(address deployer);
      event DeploymentApprovalRevoked(address deployer);
      event ManyToOne_ImplementationCreated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationUpdated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationLocked(bytes32 implementationID);
      event ManyToOne_ProxyDeployed(
        bytes32 implementationID,
        address proxyAddress
      );
      event OneToOne_ProxyDeployed(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationUpdated(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationLocked(address proxyAddress);
    /* ==========  Storage  ========== */
      // Addresses allowed to deploy many-to-one proxies.
      mapping(address => bool) internal _approvedDeployers;
      // Maps implementation holders to their implementation IDs.
      mapping(bytes32 => address) internal _implementationHolders;
      // Maps implementation holders & proxy addresses to bool stating if they are locked.
      mapping(address => bool) internal _lockedImplementations;
      // Temporary value used in the many-to-one proxy constructor.
      // The many-to-one proxy contract is deployed with create2 and
      // uses static initialization code for simple address derivation,
      // so it calls the proxy manager in the constructor to get this
      // address in order to save it as an immutable in the bytecode.
      address internal _implementationHolder;
    /* ==========  Modifiers  ========== */
      modifier onlyApprovedDeployer {
        address sender = _msgSender();
        require(_approvedDeployers[sender] || sender == owner(), "ERR_NOT_APPROVED");
        _;
      }
    /* ==========  Constructor  ========== */
      constructor() public Ownable() {}
    /* ==========  Access Control  ========== */
      /**
       * @dev Allows `deployer` to deploy many-to-one proxies.
       */
      function approveDeployer(address deployer) external override onlyOwner {
        _approvedDeployers[deployer] = true;
        emit DeploymentApprovalGranted(deployer);
      }
      /**
       * @dev Prevents `deployer` from deploying many-to-one proxies.
       */
      function revokeDeployerApproval(address deployer) external override onlyOwner {
        _approvedDeployers[deployer] = false;
        emit DeploymentApprovalRevoked(deployer);
      }
    /* ==========  Implementation Management  ========== */
      /**
       * @dev Creates a many-to-one proxy relationship.
       *
       * Deploys an implementation holder contract which stores the
       * implementation address for many proxies. The implementation
       * address can be updated on the holder to change the runtime
       * code used by all its proxies.
       *
       * @param implementationID ID for the implementation, used to identify the
       * proxies that use it. Also used as the salt in the create2 call when
       * deploying the implementation holder contract.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function createManyToOneProxyRelationship(
        bytes32 implementationID,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Deploy the implementation holder contract with the implementation
        // ID as the create2 salt.
        address implementationHolder = Create2.deploy(
          0,
          implementationID,
          type(ManyToOneImplementationHolder).creationCode
        );
        // Store the implementation holder address
        _implementationHolders[implementationID] = implementationHolder;
        // Sets the implementation address.
        _setImplementation(implementationHolder, implementation);
        emit ManyToOne_ImplementationCreated(
          implementationID,
          implementation
        );
      }
      /**
       * @dev Lock the current implementation for `implementationID` so that it can never be upgraded again.
       */
      function lockImplementationManyToOne(bytes32 implementationID) external override onlyOwner {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        _lockedImplementations[implementationHolder] = true;
        emit ManyToOne_ImplementationLocked(implementationID);
      }
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationOneToOne(address proxyAddress) external override onlyOwner {
        _lockedImplementations[proxyAddress] = true;
        emit OneToOne_ImplementationLocked(proxyAddress);
      }
      /**
       * @dev Updates the implementation address for a many-to-one
       * proxy relationship.
       *
       * @param implementationID Identifier for the implementation.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function setImplementationAddressManyToOne(
        bytes32 implementationID,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        // Verify implementation is not locked
        require(!_lockedImplementations[implementationHolder], "ERR_IMPLEMENTATION_LOCKED");
        // Set the implementation address
        _setImplementation(implementationHolder, implementation);
        emit ManyToOne_ImplementationUpdated(
          implementationID,
          implementation
        );
      }
      /**
       * @dev Updates the implementation address for a one-to-one proxy.
       *
       * Note: This could work for many-to-one as well if the caller
       * provides the implementation holder address in place of the
       * proxy address, as they use the same access control and update
       * mechanism.
       *
       * @param proxyAddress Address of the deployed proxy
       * @param implementation Address with the runtime code for
       * the proxy to use.
       */
      function setImplementationAddressOneToOne(
        address proxyAddress,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Verify proxy is not locked
        require(!_lockedImplementations[proxyAddress], "ERR_IMPLEMENTATION_LOCKED");
        // Set the implementation address
        _setImplementation(proxyAddress, implementation);
        emit OneToOne_ImplementationUpdated(proxyAddress, implementation);
      }
    /* ==========  Proxy Deployment  ========== */
      /**
       * @dev Deploy a proxy contract with a one-to-one relationship
       * with its implementation.
       *
       * The proxy will have its own implementation address which can
       * be updated by the proxy manager.
       *
       * @param suppliedSalt Salt provided by the account requesting deployment.
       * @param implementation Address of the contract with the runtime
       * code that the proxy should use.
       */
      function deployProxyOneToOne(
        bytes32 suppliedSalt,
        address implementation
      )
        external
        override
        onlyOwner
        returns(address proxyAddress)
      {
        // Derive the create2 salt from the deployment requester's address
        // and the requester-supplied salt.
        bytes32 salt = Salty.deriveOneToOneSalt(_msgSender(), suppliedSalt);
        // Deploy the proxy
        proxyAddress = Create2.deploy(
          0,
          salt,
          type(DelegateCallProxyOneToOne).creationCode
        );
        // Set the implementation address on the new proxy.
        _setImplementation(proxyAddress, implementation);
        emit OneToOne_ProxyDeployed(proxyAddress, implementation);
      }
      /**
       * @dev Deploy a proxy with a many-to-one relationship with its implemenation.
       *
       * The proxy will call the implementation holder for every transaction to
       * determine the address to use in calls.
       *
       * @param implementationID Identifier for the proxy's implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deployProxyManyToOne(bytes32 implementationID, bytes32 suppliedSalt)
        external
        override
        onlyApprovedDeployer
        returns(address proxyAddress)
      {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        // Derive the create2 salt from the deployment requester's address, the
        // implementation ID and the requester-supplied salt.
        bytes32 salt = Salty.deriveManyToOneSalt(
          _msgSender(),
          implementationID,
          suppliedSalt
        );
        // Set the implementation holder address in storage so the proxy
        // constructor can query it.
        _implementationHolder = implementationHolder;
        // Deploy the proxy, which will query the implementation holder address
        // and save it as an immutable in the contract bytecode.
        proxyAddress = Create2.deploy(
          0,
          salt,
          type(DelegateCallProxyManyToOne).creationCode
        );
        // Remove the address from temporary storage.
        _implementationHolder = address(0);
        emit ManyToOne_ProxyDeployed(
          implementationID,
          proxyAddress
        );
      }
    /* ==========  Queries  ========== */
      /**
       * @dev Returns a boolean stating whether `implementationID` is locked.
       */
      function isImplementationLocked(bytes32 implementationID) external override view returns (bool) {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        return _lockedImplementations[implementationHolder];
      }
      /**
       * @dev Returns a boolean stating whether `proxyAddress` is locked.
       */
      function isImplementationLocked(address proxyAddress) external override view returns (bool) {
        return _lockedImplementations[proxyAddress];
      }
      /**
       * @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
       * proxies.
       */
      function isApprovedDeployer(address deployer) external override view returns (bool) {
        return _approvedDeployers[deployer];
      }
      /**
       * @dev Queries the temporary storage value `_implementationHolder`.
       * This is used in the constructor of the many-to-one proxy contract
       * so that the create2 address is static (adding constructor arguments
       * would change the codehash) and the implementation holder can be
       * stored as a constant.
       */
      function getImplementationHolder()
        external
        override
        view
        returns (address)
      {
        return _implementationHolder;
      }
      /**
       * @dev Returns the address of the implementation holder contract
       * for `implementationID`.
       */
      function getImplementationHolder(
        bytes32 implementationID
      )
        external
        override
        view
        returns (address)
      {
        return _implementationHolders[implementationID];
      }
      /**
       * @dev Computes the create2 address for a one-to-one proxy requested
       * by `originator` using `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address originator,
        bytes32 suppliedSalt
      )
        external
        override
        view
        returns (address)
      {
        bytes32 salt = Salty.deriveOneToOneSalt(originator, suppliedSalt);
        return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH);
      }
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` requested by `originator` using
       * `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        external
        override
        view
        returns (address)
      {
        bytes32 salt = Salty.deriveManyToOneSalt(
          originator,
          implementationID,
          suppliedSalt
        );
        return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH);
      }
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(bytes32 implementationID)
        public
        override
        view
        returns (address)
      {
        return Create2.computeAddress(
          implementationID,
          CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH
        );
      }
    /* ==========  Internal Functions  ========== */
      /**
       * @dev Sets the implementation address for a one-to-one proxy or
       * many-to-one implementation holder. Both use the same access
       * control and update mechanism, which is the receipt of a call
       * from the proxy manager with the abi-encoded implementation address
       * as the only calldata.
       *
       * Note: Verifies that the implementation address is a contract.
       *
       * @param proxyOrHolder Address of the one-to-one proxy or
       * many-to-one implementation holder contract.
       * @param implementation Address of the contract with the runtime
       * code that the proxy or proxies should use.
       */
      function _setImplementation(
        address proxyOrHolder,
        address implementation
      ) internal {
        // Verify that the implementation address is a contract.
        require(Address.isContract(implementation), "ERR_NOT_CONTRACT");
        // Set the implementation address on the contract.
        // solium-disable-next-line security/no-low-level-calls
        (bool success,) = proxyOrHolder.call(abi.encode(implementation));
        require(success, "ERR_SET_ADDRESS_REVERT");
      }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /**
     * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
     * `CREATE2` can be used to compute in advance the address where a smart
     * contract will be deployed, which allows for interesting new mechanisms known
     * as 'counterfactual interactions'.
     *
     * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
     * information.
     */
    library Create2 {
        /**
         * @dev Deploys a contract using `CREATE2`. The address where the contract
         * will be deployed can be known in advance via {computeAddress}.
         *
         * The bytecode for a contract can be obtained from Solidity with
         * `type(contractName).creationCode`.
         *
         * Requirements:
         *
         * - `bytecode` must not be empty.
         * - `salt` must have not been used for `bytecode` already.
         * - the factory must have a balance of at least `amount`.
         * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
         */
        function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address) {
            address addr;
            require(address(this).balance >= amount, "Create2: insufficient balance");
            require(bytecode.length != 0, "Create2: bytecode length is zero");
            // solhint-disable-next-line no-inline-assembly
            assembly {
                addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            }
            require(addr != address(0), "Create2: Failed on deploy");
            return addr;
        }
        /**
         * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
         * `bytecodeHash` or `salt` will result in a new destination address.
         */
        function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
            return computeAddress(salt, bytecodeHash, address(this));
        }
        /**
         * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
         * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
         */
        function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address) {
            bytes32 _data = keccak256(
                abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
            );
            return address(uint256(_data));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.2;
    /**
     * @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 in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly { size := extcodesize(account) }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "../GSN/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    /**
     * @dev The ManyToOneImplementationHolder stores an upgradeable implementation address
     * in storage, which many-to-one proxies query at execution time to determine which
     * contract to delegate to.
     *
     * The manager can upgrade the implementation address by calling the holder with the
     * abi-encoded address as calldata. If any other account calls the implementation holder,
     * it will return the implementation address.
     *
     * This pattern was inspired by the DharmaUpgradeBeacon from 0age
     * https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/upgradeability/smart-wallet/DharmaUpgradeBeacon.sol
     */
    contract ManyToOneImplementationHolder {
    /* ---  Storage  --- */
      address internal immutable _manager;
      address internal _implementation;
    /* ---  Constructor  --- */
      constructor() public {
        _manager = msg.sender;
      }
      /**
       * @dev Fallback function for the contract.
       *
       * Used by proxies to read the implementation address and used
       * by the proxy manager to set the implementation address.
       *
       * If called by the owner, reads the implementation address from
       * calldata (must be abi-encoded) and stores it to the first slot.
       *
       * Otherwise, returns the stored implementation address.
       */
      fallback() external payable {
        if (msg.sender != _manager) {
          assembly {
            mstore(0, sload(0))
            return(0, 32)
          }
        }
        assembly { sstore(0, calldataload(0)) }
      }
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
    /**
     * @dev Proxy contract which uses an implementation address shared with many
     * other proxies.
     *
     * An implementation holder contract stores the upgradeable implementation address.
     * When the proxy is called, it queries the implementation address from the holder
     * contract and delegatecalls the returned address, forwarding the received calldata
     * and ether.
     *
     * Note: This contract does not verify that the implementation
     * address is a valid delegation target. The manager must perform
     * this safety check before updating the implementation on the holder.
     */
    contract DelegateCallProxyManyToOne is Proxy {
    /* ==========  Constants  ========== */
      // Address that stores the implementation address.
      address internal immutable _implementationHolder;
    /* ==========  Constructor  ========== */
      constructor() public {
        // Calls the sender rather than receiving the address in the constructor
        // arguments so that the address is computable using create2.
        _implementationHolder = ProxyDeployer(msg.sender).getImplementationHolder();
      }
    /* ==========  Internal Overrides  ========== */
      /**
       * @dev Queries the implementation address from the implementation holder.
       */
      function _implementation() internal override view returns (address) {
        // Queries the implementation address from the implementation holder.
        (bool success, bytes memory data) = _implementationHolder.staticcall("");
        require(success, string(data));
        address implementation = abi.decode((data), (address));
        require(implementation != address(0), "ERR_NULL_IMPLEMENTATION");
        return implementation;
      }
    }
    interface ProxyDeployer {
      function getImplementationHolder() external view returns (address);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /**
     * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
     * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
     * be specified by overriding the virtual {_implementation} function.
     * 
     * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
     * different contract through the {_delegate} function.
     * 
     * The success and return data of the delegated call will be returned back to the caller of the proxy.
     */
    abstract contract Proxy {
        /**
         * @dev Delegates the current call to `implementation`.
         * 
         * This function does not return to its internall call site, it will return directly to the external caller.
         */
        function _delegate(address implementation) internal {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
            }
        }
        /**
         * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
         * and {_fallback} should delegate.
         */
        function _implementation() internal virtual view returns (address);
        /**
         * @dev Delegates the current call to the address returned by `_implementation()`.
         * 
         * This function does not return to its internall call site, it will return directly to the external caller.
         */
        function _fallback() internal {
            _beforeFallback();
            _delegate(_implementation());
        }
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
         * function in the contract matches the call data.
         */
        fallback () payable external {
            _fallback();
        }
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
         * is empty.
         */
        receive () payable external {
            _fallback();
        }
        /**
         * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
         * call, or as part of the Solidity `fallback` or `receive` functions.
         * 
         * If overriden should call `super._beforeFallback()`.
         */
        function _beforeFallback() internal virtual {
        }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
    /**
     * @dev Upgradeable delegatecall proxy for a single contract.
     *
     * This proxy stores an implementation address which can be upgraded by the proxy manager.
     *
     * To upgrade the implementation, the manager calls the proxy with the abi encoded implementation address.
     *
     * If any other account calls the proxy, it will delegatecall the implementation address with the received
     * calldata and ether. If the call succeeds, it will return with the received returndata.
     * If it reverts, it will revert with the received revert data.
     *
     * Note: The storage slot for the implementation address is:
     * `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`
     * This slot must not be used by the implementation contract.
     *
     * Note: This contract does not verify that the implementation address is a valid delegation target.
     * The manager must perform this safety check.
     */
    contract DelegateCallProxyOneToOne is Proxy {
    /* ==========  Constants  ========== */
      address internal immutable _manager;
    /* ==========  Constructor  ========== */
      constructor() public {
        _manager = msg.sender ;
      }
    /* ==========  Internal Overrides  ========== */
      /**
       * @dev Reads the implementation address from storage.
       */
      function _implementation() internal override view returns (address) {
        address implementation;
        assembly {
          implementation := sload(
            // bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
            0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a
          )
        }
        return implementation;
      }
      /**
        * @dev Hook that is called before falling back to the implementation.
        *
        * Checks if the call is from the owner.
        * If it is, reads the abi-encoded implementation address from calldata and stores
        * it at the slot `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`,
        * then returns with no data.
        * If it is not, continues execution with the fallback function.
        */
      function _beforeFallback() internal override {
        if (msg.sender != _manager) {
          super._beforeFallback();
        } else {
          assembly {
            sstore(
              // bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
              0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a,
              calldataload(0)
            )
            return(0, 0)
          }
        }
      }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /* ---  External Libraries  --- */
    import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
    /* ---  Proxy Contracts  --- */
    import { CodeHashes } from "./CodeHashes.sol";
    /**
     * @dev Library for computing create2 salts and addresses for proxies
     * deployed by `DelegateCallProxyManager`.
     *
     * Because the proxy factory is meant to be used by multiple contracts,
     * we use a salt derivation pattern that includes the address of the
     * contract that requested the proxy deployment, a salt provided by that
     * contract and the implementation ID used (for many-to-one proxies only).
     */
    library SaltyLib {
    /* ---  Salt Derivation  --- */
      /**
       * @dev Derives the create2 salt for a many-to-one proxy.
       *
       * Many different contracts in the Indexed framework may use the
       * same implementation contract, and they all use the same init
       * code, so we derive the actual create2 salt from a combination
       * of the implementation ID, the address of the account requesting
       * deployment and the user-supplied salt.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deriveManyToOneSalt(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (bytes32)
      {
        return keccak256(
          abi.encodePacked(
            originator,
            implementationID,
            suppliedSalt
          )
        );
      }
      /**
       * @dev Derives the create2 salt for a one-to-one proxy.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deriveOneToOneSalt(
        address originator,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (bytes32)
      {
        return keccak256(abi.encodePacked(originator, suppliedSalt));
      }
    /* ---  Address Derivation  --- */
      /**
       * @dev Computes the create2 address for a one-to-one proxy deployed
       * by `deployer` (the factory) when requested by `originator` using
       * `suppliedSalt`.
       *
       * @param deployer Address of the proxy factory.
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address deployer,
        address originator,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (address)
      {
        bytes32 salt = deriveOneToOneSalt(originator, suppliedSalt);
        return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH, deployer);
      }
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` deployed by `deployer` (the factory)
       * when requested by `originator` using `suppliedSalt`.
       *
       * @param deployer Address of the proxy factory.
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address deployer,
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (address)
      {
        bytes32 salt = deriveManyToOneSalt(
          originator,
          implementationID,
          suppliedSalt
        );
        return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH, deployer);
      }
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param deployer Address of the proxy factory.
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(
        address deployer,
        bytes32 implementationID
      )
        internal
        pure
        returns (address)
      {
        return Create2.computeAddress(
          implementationID,
          CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH,
          deployer
        );
      }
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /**
     * @dev Contract that manages deployment and upgrades of delegatecall proxies.
     *
     * An implementation identifier can be created on the proxy manager which is
     * used to specify the logic address for a particular contract type, and to
     * upgrade the implementation as needed.
     *
     * A one-to-one proxy is a single proxy contract with an upgradeable implementation
     * address.
     *
     * A many-to-one proxy is a single upgradeable implementation address that may be
     * used by many proxy contracts.
     */
    interface IDelegateCallProxyManager {
    /* ==========  Events  ========== */
      event DeploymentApprovalGranted(address deployer);
      event DeploymentApprovalRevoked(address deployer);
      event ManyToOne_ImplementationCreated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationUpdated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ProxyDeployed(
        bytes32 implementationID,
        address proxyAddress
      );
      event OneToOne_ProxyDeployed(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationUpdated(
        address proxyAddress,
        address implementationAddress
      );
    /* ==========  Controls  ========== */
      /**
       * @dev Allows `deployer` to deploy many-to-one proxies.
       */
      function approveDeployer(address deployer) external;
      /**
       * @dev Prevents `deployer` from deploying many-to-one proxies.
       */
      function revokeDeployerApproval(address deployer) external;
    /* ==========  Implementation Management  ========== */
      /**
       * @dev Creates a many-to-one proxy relationship.
       *
       * Deploys an implementation holder contract which stores the
       * implementation address for many proxies. The implementation
       * address can be updated on the holder to change the runtime
       * code used by all its proxies.
       *
       * @param implementationID ID for the implementation, used to identify the
       * proxies that use it. Also used as the salt in the create2 call when
       * deploying the implementation holder contract.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function createManyToOneProxyRelationship(
        bytes32 implementationID,
        address implementation
      ) external;
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationManyToOne(bytes32 implementationID) external;
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationOneToOne(address proxyAddress) external;
      /**
       * @dev Updates the implementation address for a many-to-one
       * proxy relationship.
       *
       * @param implementationID Identifier for the implementation.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function setImplementationAddressManyToOne(
        bytes32 implementationID,
        address implementation
      ) external;
      /**
       * @dev Updates the implementation address for a one-to-one proxy.
       *
       * Note: This could work for many-to-one as well if the caller
       * provides the implementation holder address in place of the
       * proxy address, as they use the same access control and update
       * mechanism.
       *
       * @param proxyAddress Address of the deployed proxy
       * @param implementation Address with the runtime code for
       * the proxy to use.
       */
      function setImplementationAddressOneToOne(
        address proxyAddress,
        address implementation
      ) external;
    /* ==========  Proxy Deployment  ========== */
      /**
       * @dev Deploy a proxy contract with a one-to-one relationship
       * with its implementation.
       *
       * The proxy will have its own implementation address which can
       * be updated by the proxy manager.
       *
       * @param suppliedSalt Salt provided by the account requesting deployment.
       * @param implementation Address of the contract with the runtime
       * code that the proxy should use.
       */
      function deployProxyOneToOne(
        bytes32 suppliedSalt,
        address implementation
      ) external returns(address proxyAddress);
      /**
       * @dev Deploy a proxy with a many-to-one relationship with its implemenation.
       *
       * The proxy will call the implementation holder for every transaction to
       * determine the address to use in calls.
       *
       * @param implementationID Identifier for the proxy's implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deployProxyManyToOne(
        bytes32 implementationID,
        bytes32 suppliedSalt
      ) external returns(address proxyAddress);
    /* ==========  Queries  ========== */
      /**
       * @dev Returns a boolean stating whether `implementationID` is locked.
       */
      function isImplementationLocked(bytes32 implementationID) external view returns (bool);
      /**
       * @dev Returns a boolean stating whether `proxyAddress` is locked.
       */
      function isImplementationLocked(address proxyAddress) external view returns (bool);
      /**
       * @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
       * proxies.
       */
      function isApprovedDeployer(address deployer) external view returns (bool);
      /**
       * @dev Queries the temporary storage value `_implementationHolder`.
       * This is used in the constructor of the many-to-one proxy contract
       * so that the create2 address is static (adding constructor arguments
       * would change the codehash) and the implementation holder can be
       * stored as a constant.
       */
      function getImplementationHolder() external view returns (address);
      /**
       * @dev Returns the address of the implementation holder contract
       * for `implementationID`.
       */
      function getImplementationHolder(bytes32 implementationID) external view returns (address);
      /**
       * @dev Computes the create2 address for a one-to-one proxy requested
       * by `originator` using `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address originator,
        bytes32 suppliedSalt
      ) external view returns (address);
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` requested by `originator` using
       * `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      ) external view returns (address);
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(bytes32 implementationID) external view returns (address);
    }

    File 2 of 3: ManyToOneImplementationHolder
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /**
     * @dev Because we use the code hashes of the proxy contracts for proxy address
     * derivation, it is important that other packages have access to the correct
     * values when they import the salt library.
     */
    library CodeHashes {
      bytes32 internal constant ONE_TO_ONE_CODEHASH = 0x63d9f7b5931b69188c8f6b806606f25892f1bb17b7f7e966fe3a32c04493aee4;
      bytes32 internal constant MANY_TO_ONE_CODEHASH = 0xa035ad05a1663db5bfd455b99cd7c6ac6bd49269738458eda140e0b78ed53f79;
      bytes32 internal constant IMPLEMENTATION_HOLDER_CODEHASH = 0x11c370493a726a0ffa93d42b399ad046f1b5a543b6e72f1a64f1488dc1c58f2c;
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    /* ==========  External Libraries  ========== */
    import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
    import { Address } from "@openzeppelin/contracts/utils/Address.sol";
    import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
    /* ==========  Proxy Contracts  ========== */
    import "./ManyToOneImplementationHolder.sol";
    import { DelegateCallProxyManyToOne } from "./DelegateCallProxyManyToOne.sol";
    import { DelegateCallProxyOneToOne } from "./DelegateCallProxyOneToOne.sol";
    /* ==========  Internal Libraries  ========== */
    import { SaltyLib as Salty } from "./SaltyLib.sol";
    import { CodeHashes } from "./CodeHashes.sol";
    /* ==========  Inheritance  ========== */
    import "./interfaces/IDelegateCallProxyManager.sol";
    /**
     * @dev Contract that manages deployment and upgrades of delegatecall proxies.
     *
     * An implementation identifier can be created on the proxy manager which is
     * used to specify the logic address for a particular contract type, and to
     * upgrade the implementation as needed.
     *
     * ====== Proxy Types ======
     * A one-to-one proxy is a single proxy contract with an upgradeable implementation
     * address.
     *
     * A many-to-one proxy is a single upgradeable implementation address that may be
     * used by many proxy contracts.
     *
     * ====== Access Control ======
     * The proxy manager has a single address as its owner.
     *
     * The owner is the sole account with the following permissions:
     * - Create new many-to-one implementations
     * - Create new one-to-one proxies
     * - Modify the implementation address of existing proxies
     * - Lock proxies
     * - Designate approved deployers
     * - Remove approved deployers
     * - Modify the owner address
     *
     * Approved deployers may only deploy many-to-one proxies.
     *
     * ====== Upgrades ======
     * Proxies can be upgraded by the owner if they are not locked.
     *
     * Many-to-one proxy implementations are upgraded by calling the holder contract
     * for the implementation ID being upgraded.
     * One-to-one proxies are upgraded by calling the proxy contract directly.
     *
     * The owner can lock a one-to-one proxy or many-to-one implementation ID so that
     * it becomes impossible to upgrade.
     */
    contract DelegateCallProxyManager is Ownable, IDelegateCallProxyManager {
    /* ==========  Events  ========== */
      event DeploymentApprovalGranted(address deployer);
      event DeploymentApprovalRevoked(address deployer);
      event ManyToOne_ImplementationCreated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationUpdated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationLocked(bytes32 implementationID);
      event ManyToOne_ProxyDeployed(
        bytes32 implementationID,
        address proxyAddress
      );
      event OneToOne_ProxyDeployed(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationUpdated(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationLocked(address proxyAddress);
    /* ==========  Storage  ========== */
      // Addresses allowed to deploy many-to-one proxies.
      mapping(address => bool) internal _approvedDeployers;
      // Maps implementation holders to their implementation IDs.
      mapping(bytes32 => address) internal _implementationHolders;
      // Maps implementation holders & proxy addresses to bool stating if they are locked.
      mapping(address => bool) internal _lockedImplementations;
      // Temporary value used in the many-to-one proxy constructor.
      // The many-to-one proxy contract is deployed with create2 and
      // uses static initialization code for simple address derivation,
      // so it calls the proxy manager in the constructor to get this
      // address in order to save it as an immutable in the bytecode.
      address internal _implementationHolder;
    /* ==========  Modifiers  ========== */
      modifier onlyApprovedDeployer {
        address sender = _msgSender();
        require(_approvedDeployers[sender] || sender == owner(), "ERR_NOT_APPROVED");
        _;
      }
    /* ==========  Constructor  ========== */
      constructor() public Ownable() {}
    /* ==========  Access Control  ========== */
      /**
       * @dev Allows `deployer` to deploy many-to-one proxies.
       */
      function approveDeployer(address deployer) external override onlyOwner {
        _approvedDeployers[deployer] = true;
        emit DeploymentApprovalGranted(deployer);
      }
      /**
       * @dev Prevents `deployer` from deploying many-to-one proxies.
       */
      function revokeDeployerApproval(address deployer) external override onlyOwner {
        _approvedDeployers[deployer] = false;
        emit DeploymentApprovalRevoked(deployer);
      }
    /* ==========  Implementation Management  ========== */
      /**
       * @dev Creates a many-to-one proxy relationship.
       *
       * Deploys an implementation holder contract which stores the
       * implementation address for many proxies. The implementation
       * address can be updated on the holder to change the runtime
       * code used by all its proxies.
       *
       * @param implementationID ID for the implementation, used to identify the
       * proxies that use it. Also used as the salt in the create2 call when
       * deploying the implementation holder contract.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function createManyToOneProxyRelationship(
        bytes32 implementationID,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Deploy the implementation holder contract with the implementation
        // ID as the create2 salt.
        address implementationHolder = Create2.deploy(
          0,
          implementationID,
          type(ManyToOneImplementationHolder).creationCode
        );
        // Store the implementation holder address
        _implementationHolders[implementationID] = implementationHolder;
        // Sets the implementation address.
        _setImplementation(implementationHolder, implementation);
        emit ManyToOne_ImplementationCreated(
          implementationID,
          implementation
        );
      }
      /**
       * @dev Lock the current implementation for `implementationID` so that it can never be upgraded again.
       */
      function lockImplementationManyToOne(bytes32 implementationID) external override onlyOwner {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        _lockedImplementations[implementationHolder] = true;
        emit ManyToOne_ImplementationLocked(implementationID);
      }
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationOneToOne(address proxyAddress) external override onlyOwner {
        _lockedImplementations[proxyAddress] = true;
        emit OneToOne_ImplementationLocked(proxyAddress);
      }
      /**
       * @dev Updates the implementation address for a many-to-one
       * proxy relationship.
       *
       * @param implementationID Identifier for the implementation.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function setImplementationAddressManyToOne(
        bytes32 implementationID,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        // Verify implementation is not locked
        require(!_lockedImplementations[implementationHolder], "ERR_IMPLEMENTATION_LOCKED");
        // Set the implementation address
        _setImplementation(implementationHolder, implementation);
        emit ManyToOne_ImplementationUpdated(
          implementationID,
          implementation
        );
      }
      /**
       * @dev Updates the implementation address for a one-to-one proxy.
       *
       * Note: This could work for many-to-one as well if the caller
       * provides the implementation holder address in place of the
       * proxy address, as they use the same access control and update
       * mechanism.
       *
       * @param proxyAddress Address of the deployed proxy
       * @param implementation Address with the runtime code for
       * the proxy to use.
       */
      function setImplementationAddressOneToOne(
        address proxyAddress,
        address implementation
      )
        external
        override
        onlyOwner
      {
        // Verify proxy is not locked
        require(!_lockedImplementations[proxyAddress], "ERR_IMPLEMENTATION_LOCKED");
        // Set the implementation address
        _setImplementation(proxyAddress, implementation);
        emit OneToOne_ImplementationUpdated(proxyAddress, implementation);
      }
    /* ==========  Proxy Deployment  ========== */
      /**
       * @dev Deploy a proxy contract with a one-to-one relationship
       * with its implementation.
       *
       * The proxy will have its own implementation address which can
       * be updated by the proxy manager.
       *
       * @param suppliedSalt Salt provided by the account requesting deployment.
       * @param implementation Address of the contract with the runtime
       * code that the proxy should use.
       */
      function deployProxyOneToOne(
        bytes32 suppliedSalt,
        address implementation
      )
        external
        override
        onlyOwner
        returns(address proxyAddress)
      {
        // Derive the create2 salt from the deployment requester's address
        // and the requester-supplied salt.
        bytes32 salt = Salty.deriveOneToOneSalt(_msgSender(), suppliedSalt);
        // Deploy the proxy
        proxyAddress = Create2.deploy(
          0,
          salt,
          type(DelegateCallProxyOneToOne).creationCode
        );
        // Set the implementation address on the new proxy.
        _setImplementation(proxyAddress, implementation);
        emit OneToOne_ProxyDeployed(proxyAddress, implementation);
      }
      /**
       * @dev Deploy a proxy with a many-to-one relationship with its implemenation.
       *
       * The proxy will call the implementation holder for every transaction to
       * determine the address to use in calls.
       *
       * @param implementationID Identifier for the proxy's implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deployProxyManyToOne(bytes32 implementationID, bytes32 suppliedSalt)
        external
        override
        onlyApprovedDeployer
        returns(address proxyAddress)
      {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        // Derive the create2 salt from the deployment requester's address, the
        // implementation ID and the requester-supplied salt.
        bytes32 salt = Salty.deriveManyToOneSalt(
          _msgSender(),
          implementationID,
          suppliedSalt
        );
        // Set the implementation holder address in storage so the proxy
        // constructor can query it.
        _implementationHolder = implementationHolder;
        // Deploy the proxy, which will query the implementation holder address
        // and save it as an immutable in the contract bytecode.
        proxyAddress = Create2.deploy(
          0,
          salt,
          type(DelegateCallProxyManyToOne).creationCode
        );
        // Remove the address from temporary storage.
        _implementationHolder = address(0);
        emit ManyToOne_ProxyDeployed(
          implementationID,
          proxyAddress
        );
      }
    /* ==========  Queries  ========== */
      /**
       * @dev Returns a boolean stating whether `implementationID` is locked.
       */
      function isImplementationLocked(bytes32 implementationID) external override view returns (bool) {
        // Read the implementation holder address from storage.
        address implementationHolder = _implementationHolders[implementationID];
        // Verify that the implementation exists.
        require(implementationHolder != address(0), "ERR_IMPLEMENTATION_ID");
        return _lockedImplementations[implementationHolder];
      }
      /**
       * @dev Returns a boolean stating whether `proxyAddress` is locked.
       */
      function isImplementationLocked(address proxyAddress) external override view returns (bool) {
        return _lockedImplementations[proxyAddress];
      }
      /**
       * @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
       * proxies.
       */
      function isApprovedDeployer(address deployer) external override view returns (bool) {
        return _approvedDeployers[deployer];
      }
      /**
       * @dev Queries the temporary storage value `_implementationHolder`.
       * This is used in the constructor of the many-to-one proxy contract
       * so that the create2 address is static (adding constructor arguments
       * would change the codehash) and the implementation holder can be
       * stored as a constant.
       */
      function getImplementationHolder()
        external
        override
        view
        returns (address)
      {
        return _implementationHolder;
      }
      /**
       * @dev Returns the address of the implementation holder contract
       * for `implementationID`.
       */
      function getImplementationHolder(
        bytes32 implementationID
      )
        external
        override
        view
        returns (address)
      {
        return _implementationHolders[implementationID];
      }
      /**
       * @dev Computes the create2 address for a one-to-one proxy requested
       * by `originator` using `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address originator,
        bytes32 suppliedSalt
      )
        external
        override
        view
        returns (address)
      {
        bytes32 salt = Salty.deriveOneToOneSalt(originator, suppliedSalt);
        return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH);
      }
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` requested by `originator` using
       * `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        external
        override
        view
        returns (address)
      {
        bytes32 salt = Salty.deriveManyToOneSalt(
          originator,
          implementationID,
          suppliedSalt
        );
        return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH);
      }
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(bytes32 implementationID)
        public
        override
        view
        returns (address)
      {
        return Create2.computeAddress(
          implementationID,
          CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH
        );
      }
    /* ==========  Internal Functions  ========== */
      /**
       * @dev Sets the implementation address for a one-to-one proxy or
       * many-to-one implementation holder. Both use the same access
       * control and update mechanism, which is the receipt of a call
       * from the proxy manager with the abi-encoded implementation address
       * as the only calldata.
       *
       * Note: Verifies that the implementation address is a contract.
       *
       * @param proxyOrHolder Address of the one-to-one proxy or
       * many-to-one implementation holder contract.
       * @param implementation Address of the contract with the runtime
       * code that the proxy or proxies should use.
       */
      function _setImplementation(
        address proxyOrHolder,
        address implementation
      ) internal {
        // Verify that the implementation address is a contract.
        require(Address.isContract(implementation), "ERR_NOT_CONTRACT");
        // Set the implementation address on the contract.
        // solium-disable-next-line security/no-low-level-calls
        (bool success,) = proxyOrHolder.call(abi.encode(implementation));
        require(success, "ERR_SET_ADDRESS_REVERT");
      }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /**
     * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
     * `CREATE2` can be used to compute in advance the address where a smart
     * contract will be deployed, which allows for interesting new mechanisms known
     * as 'counterfactual interactions'.
     *
     * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
     * information.
     */
    library Create2 {
        /**
         * @dev Deploys a contract using `CREATE2`. The address where the contract
         * will be deployed can be known in advance via {computeAddress}.
         *
         * The bytecode for a contract can be obtained from Solidity with
         * `type(contractName).creationCode`.
         *
         * Requirements:
         *
         * - `bytecode` must not be empty.
         * - `salt` must have not been used for `bytecode` already.
         * - the factory must have a balance of at least `amount`.
         * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
         */
        function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address) {
            address addr;
            require(address(this).balance >= amount, "Create2: insufficient balance");
            require(bytecode.length != 0, "Create2: bytecode length is zero");
            // solhint-disable-next-line no-inline-assembly
            assembly {
                addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            }
            require(addr != address(0), "Create2: Failed on deploy");
            return addr;
        }
        /**
         * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
         * `bytecodeHash` or `salt` will result in a new destination address.
         */
        function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
            return computeAddress(salt, bytecodeHash, address(this));
        }
        /**
         * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
         * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
         */
        function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address) {
            bytes32 _data = keccak256(
                abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
            );
            return address(uint256(_data));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.2;
    /**
     * @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 in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly { size := extcodesize(account) }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{ value: amount }("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
        /**
         * @dev Performs a Solidity function call using a low level `call`. A
         * plain`call` is an unsafe replacement for a function call: use this
         * function instead.
         *
         * If `target` reverts with a revert reason, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Returns the raw returned data. To convert to the expected return value,
         * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
          return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            return _functionCallWithValue(target, data, value, errorMessage);
        }
        function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    import "../GSN/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(_owner == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    /**
     * @dev The ManyToOneImplementationHolder stores an upgradeable implementation address
     * in storage, which many-to-one proxies query at execution time to determine which
     * contract to delegate to.
     *
     * The manager can upgrade the implementation address by calling the holder with the
     * abi-encoded address as calldata. If any other account calls the implementation holder,
     * it will return the implementation address.
     *
     * This pattern was inspired by the DharmaUpgradeBeacon from 0age
     * https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/upgradeability/smart-wallet/DharmaUpgradeBeacon.sol
     */
    contract ManyToOneImplementationHolder {
    /* ---  Storage  --- */
      address internal immutable _manager;
      address internal _implementation;
    /* ---  Constructor  --- */
      constructor() public {
        _manager = msg.sender;
      }
      /**
       * @dev Fallback function for the contract.
       *
       * Used by proxies to read the implementation address and used
       * by the proxy manager to set the implementation address.
       *
       * If called by the owner, reads the implementation address from
       * calldata (must be abi-encoded) and stores it to the first slot.
       *
       * Otherwise, returns the stored implementation address.
       */
      fallback() external payable {
        if (msg.sender != _manager) {
          assembly {
            mstore(0, sload(0))
            return(0, 32)
          }
        }
        assembly { sstore(0, calldataload(0)) }
      }
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
    /**
     * @dev Proxy contract which uses an implementation address shared with many
     * other proxies.
     *
     * An implementation holder contract stores the upgradeable implementation address.
     * When the proxy is called, it queries the implementation address from the holder
     * contract and delegatecalls the returned address, forwarding the received calldata
     * and ether.
     *
     * Note: This contract does not verify that the implementation
     * address is a valid delegation target. The manager must perform
     * this safety check before updating the implementation on the holder.
     */
    contract DelegateCallProxyManyToOne is Proxy {
    /* ==========  Constants  ========== */
      // Address that stores the implementation address.
      address internal immutable _implementationHolder;
    /* ==========  Constructor  ========== */
      constructor() public {
        // Calls the sender rather than receiving the address in the constructor
        // arguments so that the address is computable using create2.
        _implementationHolder = ProxyDeployer(msg.sender).getImplementationHolder();
      }
    /* ==========  Internal Overrides  ========== */
      /**
       * @dev Queries the implementation address from the implementation holder.
       */
      function _implementation() internal override view returns (address) {
        // Queries the implementation address from the implementation holder.
        (bool success, bytes memory data) = _implementationHolder.staticcall("");
        require(success, string(data));
        address implementation = abi.decode((data), (address));
        require(implementation != address(0), "ERR_NULL_IMPLEMENTATION");
        return implementation;
      }
    }
    interface ProxyDeployer {
      function getImplementationHolder() external view returns (address);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    /**
     * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
     * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
     * be specified by overriding the virtual {_implementation} function.
     * 
     * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
     * different contract through the {_delegate} function.
     * 
     * The success and return data of the delegated call will be returned back to the caller of the proxy.
     */
    abstract contract Proxy {
        /**
         * @dev Delegates the current call to `implementation`.
         * 
         * This function does not return to its internall call site, it will return directly to the external caller.
         */
        function _delegate(address implementation) internal {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
            }
        }
        /**
         * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
         * and {_fallback} should delegate.
         */
        function _implementation() internal virtual view returns (address);
        /**
         * @dev Delegates the current call to the address returned by `_implementation()`.
         * 
         * This function does not return to its internall call site, it will return directly to the external caller.
         */
        function _fallback() internal {
            _beforeFallback();
            _delegate(_implementation());
        }
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
         * function in the contract matches the call data.
         */
        fallback () payable external {
            _fallback();
        }
        /**
         * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
         * is empty.
         */
        receive () payable external {
            _fallback();
        }
        /**
         * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
         * call, or as part of the Solidity `fallback` or `receive` functions.
         * 
         * If overriden should call `super._beforeFallback()`.
         */
        function _beforeFallback() internal virtual {
        }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity =0.6.12;
    import { Proxy } from "@openzeppelin/contracts/proxy/Proxy.sol";
    /**
     * @dev Upgradeable delegatecall proxy for a single contract.
     *
     * This proxy stores an implementation address which can be upgraded by the proxy manager.
     *
     * To upgrade the implementation, the manager calls the proxy with the abi encoded implementation address.
     *
     * If any other account calls the proxy, it will delegatecall the implementation address with the received
     * calldata and ether. If the call succeeds, it will return with the received returndata.
     * If it reverts, it will revert with the received revert data.
     *
     * Note: The storage slot for the implementation address is:
     * `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`
     * This slot must not be used by the implementation contract.
     *
     * Note: This contract does not verify that the implementation address is a valid delegation target.
     * The manager must perform this safety check.
     */
    contract DelegateCallProxyOneToOne is Proxy {
    /* ==========  Constants  ========== */
      address internal immutable _manager;
    /* ==========  Constructor  ========== */
      constructor() public {
        _manager = msg.sender ;
      }
    /* ==========  Internal Overrides  ========== */
      /**
       * @dev Reads the implementation address from storage.
       */
      function _implementation() internal override view returns (address) {
        address implementation;
        assembly {
          implementation := sload(
            // bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
            0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a
          )
        }
        return implementation;
      }
      /**
        * @dev Hook that is called before falling back to the implementation.
        *
        * Checks if the call is from the owner.
        * If it is, reads the abi-encoded implementation address from calldata and stores
        * it at the slot `bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)`,
        * then returns with no data.
        * If it is not, continues execution with the fallback function.
        */
      function _beforeFallback() internal override {
        if (msg.sender != _manager) {
          super._beforeFallback();
        } else {
          assembly {
            sstore(
              // bytes32(uint256(keccak256("IMPLEMENTATION_ADDRESS")) + 1)
              0x913bd12b32b36f36cedaeb6e043912bceb97022755958701789d3108d33a045a,
              calldataload(0)
            )
            return(0, 0)
          }
        }
      }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /* ---  External Libraries  --- */
    import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol";
    /* ---  Proxy Contracts  --- */
    import { CodeHashes } from "./CodeHashes.sol";
    /**
     * @dev Library for computing create2 salts and addresses for proxies
     * deployed by `DelegateCallProxyManager`.
     *
     * Because the proxy factory is meant to be used by multiple contracts,
     * we use a salt derivation pattern that includes the address of the
     * contract that requested the proxy deployment, a salt provided by that
     * contract and the implementation ID used (for many-to-one proxies only).
     */
    library SaltyLib {
    /* ---  Salt Derivation  --- */
      /**
       * @dev Derives the create2 salt for a many-to-one proxy.
       *
       * Many different contracts in the Indexed framework may use the
       * same implementation contract, and they all use the same init
       * code, so we derive the actual create2 salt from a combination
       * of the implementation ID, the address of the account requesting
       * deployment and the user-supplied salt.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deriveManyToOneSalt(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (bytes32)
      {
        return keccak256(
          abi.encodePacked(
            originator,
            implementationID,
            suppliedSalt
          )
        );
      }
      /**
       * @dev Derives the create2 salt for a one-to-one proxy.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deriveOneToOneSalt(
        address originator,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (bytes32)
      {
        return keccak256(abi.encodePacked(originator, suppliedSalt));
      }
    /* ---  Address Derivation  --- */
      /**
       * @dev Computes the create2 address for a one-to-one proxy deployed
       * by `deployer` (the factory) when requested by `originator` using
       * `suppliedSalt`.
       *
       * @param deployer Address of the proxy factory.
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address deployer,
        address originator,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (address)
      {
        bytes32 salt = deriveOneToOneSalt(originator, suppliedSalt);
        return Create2.computeAddress(salt, CodeHashes.ONE_TO_ONE_CODEHASH, deployer);
      }
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` deployed by `deployer` (the factory)
       * when requested by `originator` using `suppliedSalt`.
       *
       * @param deployer Address of the proxy factory.
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address deployer,
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      )
        internal
        pure
        returns (address)
      {
        bytes32 salt = deriveManyToOneSalt(
          originator,
          implementationID,
          suppliedSalt
        );
        return Create2.computeAddress(salt, CodeHashes.MANY_TO_ONE_CODEHASH, deployer);
      }
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param deployer Address of the proxy factory.
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(
        address deployer,
        bytes32 implementationID
      )
        internal
        pure
        returns (address)
      {
        return Create2.computeAddress(
          implementationID,
          CodeHashes.IMPLEMENTATION_HOLDER_CODEHASH,
          deployer
        );
      }
    }// SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /**
     * @dev Contract that manages deployment and upgrades of delegatecall proxies.
     *
     * An implementation identifier can be created on the proxy manager which is
     * used to specify the logic address for a particular contract type, and to
     * upgrade the implementation as needed.
     *
     * A one-to-one proxy is a single proxy contract with an upgradeable implementation
     * address.
     *
     * A many-to-one proxy is a single upgradeable implementation address that may be
     * used by many proxy contracts.
     */
    interface IDelegateCallProxyManager {
    /* ==========  Events  ========== */
      event DeploymentApprovalGranted(address deployer);
      event DeploymentApprovalRevoked(address deployer);
      event ManyToOne_ImplementationCreated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ImplementationUpdated(
        bytes32 implementationID,
        address implementationAddress
      );
      event ManyToOne_ProxyDeployed(
        bytes32 implementationID,
        address proxyAddress
      );
      event OneToOne_ProxyDeployed(
        address proxyAddress,
        address implementationAddress
      );
      event OneToOne_ImplementationUpdated(
        address proxyAddress,
        address implementationAddress
      );
    /* ==========  Controls  ========== */
      /**
       * @dev Allows `deployer` to deploy many-to-one proxies.
       */
      function approveDeployer(address deployer) external;
      /**
       * @dev Prevents `deployer` from deploying many-to-one proxies.
       */
      function revokeDeployerApproval(address deployer) external;
    /* ==========  Implementation Management  ========== */
      /**
       * @dev Creates a many-to-one proxy relationship.
       *
       * Deploys an implementation holder contract which stores the
       * implementation address for many proxies. The implementation
       * address can be updated on the holder to change the runtime
       * code used by all its proxies.
       *
       * @param implementationID ID for the implementation, used to identify the
       * proxies that use it. Also used as the salt in the create2 call when
       * deploying the implementation holder contract.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function createManyToOneProxyRelationship(
        bytes32 implementationID,
        address implementation
      ) external;
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationManyToOne(bytes32 implementationID) external;
      /**
       * @dev Lock the current implementation for `proxyAddress` so that it can never be upgraded again.
       */
      function lockImplementationOneToOne(address proxyAddress) external;
      /**
       * @dev Updates the implementation address for a many-to-one
       * proxy relationship.
       *
       * @param implementationID Identifier for the implementation.
       * @param implementation Address with the runtime code the proxies
       * should use.
       */
      function setImplementationAddressManyToOne(
        bytes32 implementationID,
        address implementation
      ) external;
      /**
       * @dev Updates the implementation address for a one-to-one proxy.
       *
       * Note: This could work for many-to-one as well if the caller
       * provides the implementation holder address in place of the
       * proxy address, as they use the same access control and update
       * mechanism.
       *
       * @param proxyAddress Address of the deployed proxy
       * @param implementation Address with the runtime code for
       * the proxy to use.
       */
      function setImplementationAddressOneToOne(
        address proxyAddress,
        address implementation
      ) external;
    /* ==========  Proxy Deployment  ========== */
      /**
       * @dev Deploy a proxy contract with a one-to-one relationship
       * with its implementation.
       *
       * The proxy will have its own implementation address which can
       * be updated by the proxy manager.
       *
       * @param suppliedSalt Salt provided by the account requesting deployment.
       * @param implementation Address of the contract with the runtime
       * code that the proxy should use.
       */
      function deployProxyOneToOne(
        bytes32 suppliedSalt,
        address implementation
      ) external returns(address proxyAddress);
      /**
       * @dev Deploy a proxy with a many-to-one relationship with its implemenation.
       *
       * The proxy will call the implementation holder for every transaction to
       * determine the address to use in calls.
       *
       * @param implementationID Identifier for the proxy's implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function deployProxyManyToOne(
        bytes32 implementationID,
        bytes32 suppliedSalt
      ) external returns(address proxyAddress);
    /* ==========  Queries  ========== */
      /**
       * @dev Returns a boolean stating whether `implementationID` is locked.
       */
      function isImplementationLocked(bytes32 implementationID) external view returns (bool);
      /**
       * @dev Returns a boolean stating whether `proxyAddress` is locked.
       */
      function isImplementationLocked(address proxyAddress) external view returns (bool);
      /**
       * @dev Returns a boolean stating whether `deployer` is allowed to deploy many-to-one
       * proxies.
       */
      function isApprovedDeployer(address deployer) external view returns (bool);
      /**
       * @dev Queries the temporary storage value `_implementationHolder`.
       * This is used in the constructor of the many-to-one proxy contract
       * so that the create2 address is static (adding constructor arguments
       * would change the codehash) and the implementation holder can be
       * stored as a constant.
       */
      function getImplementationHolder() external view returns (address);
      /**
       * @dev Returns the address of the implementation holder contract
       * for `implementationID`.
       */
      function getImplementationHolder(bytes32 implementationID) external view returns (address);
      /**
       * @dev Computes the create2 address for a one-to-one proxy requested
       * by `originator` using `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param suppliedSalt Salt provided by the account requesting deployment.
       */
      function computeProxyAddressOneToOne(
        address originator,
        bytes32 suppliedSalt
      ) external view returns (address);
      /**
       * @dev Computes the create2 address for a many-to-one proxy for the
       * implementation `implementationID` requested by `originator` using
       * `suppliedSalt`.
       *
       * @param originator Address of the account requesting deployment.
       * @param implementationID The identifier for the contract implementation.
       * @param suppliedSalt Salt provided by the account requesting deployment.
      */
      function computeProxyAddressManyToOne(
        address originator,
        bytes32 implementationID,
        bytes32 suppliedSalt
      ) external view returns (address);
      /**
       * @dev Computes the create2 address of the implementation holder
       * for `implementationID`.
       *
       * @param implementationID The identifier for the contract implementation.
      */
      function computeHolderAddressManyToOne(bytes32 implementationID) external view returns (address);
    }

    File 3 of 3: SigmaIndexPoolV1
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    /************************************************************************************************
    Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BConst.sol
    This source code has been modified from the original, which was copied from the github repository
    at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f.
    Subject to the GPL-3.0 license
    *************************************************************************************************/
    contract BConst {
      uint256 public constant VERSION_NUMBER = 1;
    /* ---  Weight Updates  --- */
      // Minimum time passed between each weight update for a token.
      uint256 internal constant WEIGHT_UPDATE_DELAY = 1 hours;
      // Maximum percent by which a weight can adjust at a time
      // relative to the current weight.
      // The number of iterations needed to move from weight A to weight B is the floor of:
      // (A > B): (ln(A) - ln(B)) / ln(1.01)
      // (B > A): (ln(A) - ln(B)) / ln(0.99)
      uint256 internal constant WEIGHT_CHANGE_PCT = BONE/100;
      uint256 internal constant BONE = 10**18;
      uint256 internal constant MIN_BOUND_TOKENS = 2;
      uint256 internal constant MAX_BOUND_TOKENS = 10;
      // Minimum swap fee.
      uint256 internal constant MIN_FEE = BONE / 10**6;
      // Maximum swap or exit fee.
      uint256 internal constant MAX_FEE = BONE / 10;
      // Actual exit fee.
      uint256 internal constant EXIT_FEE = 5e15;
      // Default total of all desired weights. Can differ by up to BONE.
      uint256 internal constant DEFAULT_TOTAL_WEIGHT = BONE * 25;
      // Minimum weight for any token (1/100).
      uint256 internal constant MIN_WEIGHT = BONE / 4;
      uint256 internal constant MAX_WEIGHT = BONE * 25;
      // Maximum total weight.
      uint256 internal constant MAX_TOTAL_WEIGHT = BONE * 26;
      // Minimum balance for a token (only applied at initialization)
      uint256 internal constant MIN_BALANCE = BONE / 10**12;
      // Initial pool tokens
      uint256 internal constant INIT_POOL_SUPPLY = BONE * 100;
      uint256 internal constant MIN_BPOW_BASE = 1 wei;
      uint256 internal constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;
      uint256 internal constant BPOW_PRECISION = BONE / 10**10;
      // Maximum ratio of input tokens to balance for swaps.
      uint256 internal constant MAX_IN_RATIO = BONE / 2;
      // Maximum ratio of output tokens to balance for swaps.
      uint256 internal constant MAX_OUT_RATIO = (BONE / 3) + 1 wei;
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    import "./BNum.sol";
    /************************************************************************************************
    Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BMath.sol
    This source code has been modified from the original, which was copied from the github repository
    at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f.
    Subject to the GPL-3.0 license
    *************************************************************************************************/
    contract BMath is BConst, BNum {
      /**********************************************************************************************
        // calcSpotPrice                                                                             //
        // sP = spotPrice                                                                            //
        // bI = tokenBalanceIn                ( bI / wI )         1                                  //
        // bO = tokenBalanceOut         sP =  -----------  *  ----------                             //
        // wI = tokenWeightIn                 ( bO / wO )     ( 1 - sF )                             //
        // wO = tokenWeightOut                                                                       //
        // sF = swapFee                                                                              //
        **********************************************************************************************/
      function calcSpotPrice(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 swapFee
      ) internal pure returns (uint256 spotPrice) {
        uint256 numer = bdiv(tokenBalanceIn, tokenWeightIn);
        uint256 denom = bdiv(tokenBalanceOut, tokenWeightOut);
        uint256 ratio = bdiv(numer, denom);
        uint256 scale = bdiv(BONE, bsub(BONE, swapFee));
        return (spotPrice = bmul(ratio, scale));
      }
      /**********************************************************************************************
        // calcOutGivenIn                                                                            //
        // aO = tokenAmountOut                                                                       //
        // bO = tokenBalanceOut                                                                      //
        // bI = tokenBalanceIn              /      /            bI             \\    (wI / wO) \\      //
        // aI = tokenAmountIn    aO = bO * |  1 - | --------------------------  | ^            |     //
        // wI = tokenWeightIn               \\      \\ ( bI + ( aI * ( 1 - sF )) /              /      //
        // wO = tokenWeightOut                                                                       //
        // sF = swapFee                                                                              //
        **********************************************************************************************/
      function calcOutGivenIn(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountIn,
        uint256 swapFee
      ) internal pure returns (uint256 tokenAmountOut) {
        uint256 weightRatio = bdiv(tokenWeightIn, tokenWeightOut);
        uint256 adjustedIn = bsub(BONE, swapFee);
        adjustedIn = bmul(tokenAmountIn, adjustedIn);
        uint256 y = bdiv(tokenBalanceIn, badd(tokenBalanceIn, adjustedIn));
        uint256 foo = bpow(y, weightRatio);
        uint256 bar = bsub(BONE, foo);
        tokenAmountOut = bmul(tokenBalanceOut, bar);
        return tokenAmountOut;
      }
      /**********************************************************************************************
        // calcInGivenOut                                                                            //
        // aI = tokenAmountIn                                                                        //
        // bO = tokenBalanceOut               /  /     bO      \\    (wO / wI)      \\                 //
        // bI = tokenBalanceIn          bI * |  | ------------  | ^            - 1  |                //
        // aO = tokenAmountOut    aI =        \\  \\ ( bO - aO ) /                   /                 //
        // wI = tokenWeightIn           --------------------------------------------                 //
        // wO = tokenWeightOut                          ( 1 - sF )                                   //
        // sF = swapFee                                                                              //
        **********************************************************************************************/
      function calcInGivenOut(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 tokenAmountOut,
        uint256 swapFee
      ) internal pure returns (uint256 tokenAmountIn) {
        uint256 weightRatio = bdiv(tokenWeightOut, tokenWeightIn);
        uint256 diff = bsub(tokenBalanceOut, tokenAmountOut);
        uint256 y = bdiv(tokenBalanceOut, diff);
        uint256 foo = bpow(y, weightRatio);
        foo = bsub(foo, BONE);
        tokenAmountIn = bsub(BONE, swapFee);
        tokenAmountIn = bdiv(bmul(tokenBalanceIn, foo), tokenAmountIn);
        return tokenAmountIn;
      }
      /**********************************************************************************************
        // calcPoolOutGivenSingleIn                                                                  //
        // pAo = poolAmountOut         /                                              \\              //
        // tAi = tokenAmountIn        ///      /     //    wI \\      \\\\       \\     wI \\             //
        // wI = tokenWeightIn        //| tAi *| 1 - || 1 - --  | * sF || + tBi \\    --  \\            //
        // tW = totalWeight     pAo=||  \\      \\     \\\\    tW /      //         | ^ tW   | * pS - pS //
        // tBi = tokenBalanceIn      \\\\  ------------------------------------- /        /            //
        // pS = poolSupply            \\\\                    tBi               /        /             //
        // sF = swapFee                \\                                              /              //
        **********************************************************************************************/
      function calcPoolOutGivenSingleIn(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 tokenAmountIn,
        uint256 swapFee
      ) internal pure returns (uint256 poolAmountOut) {
        // Charge the trading fee for the proportion of tokenAi
        ///  which is implicitly traded to the other pool tokens.
        // That proportion is (1- weightTokenIn)
        // tokenAiAfterFee = tAi * (1 - (1-weightTi) * poolFee);
        uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight);
        uint256 zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
        uint256 tokenAmountInAfterFee = bmul(tokenAmountIn, bsub(BONE, zaz));
        uint256 newTokenBalanceIn = badd(tokenBalanceIn, tokenAmountInAfterFee);
        uint256 tokenInRatio = bdiv(newTokenBalanceIn, tokenBalanceIn);
        // uint newPoolSupply = (ratioTi ^ weightTi) * poolSupply;
        uint256 poolRatio = bpow(tokenInRatio, normalizedWeight);
        uint256 newPoolSupply = bmul(poolRatio, poolSupply);
        poolAmountOut = bsub(newPoolSupply, poolSupply);
        return poolAmountOut;
      }
      /**********************************************************************************************
        // calcSingleInGivenPoolOut                                                                  //
        // tAi = tokenAmountIn              //(pS + pAo)\\     /    1    \\\\                           //
        // pS = poolSupply                 || ---------  | ^ | --------- || * bI - bI                //
        // pAo = poolAmountOut              \\\\    pS    /     \\(wI / tW)//                           //
        // bI = balanceIn          tAi =  --------------------------------------------               //
        // wI = weightIn                              /      wI  \\                                   //
        // tW = totalWeight                          |  1 - ----  |  * sF                            //
        // sF = swapFee                               \\      tW  /                                   //
        **********************************************************************************************/
      function calcSingleInGivenPoolOut(
        uint256 tokenBalanceIn,
        uint256 tokenWeightIn,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 poolAmountOut,
        uint256 swapFee
      ) internal pure returns (uint256 tokenAmountIn) {
        uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight);
        uint256 newPoolSupply = badd(poolSupply, poolAmountOut);
        uint256 poolRatio = bdiv(newPoolSupply, poolSupply);
        //uint newBalTi = poolRatio^(1/weightTi) * balTi;
        uint256 boo = bdiv(BONE, normalizedWeight);
        uint256 tokenInRatio = bpow(poolRatio, boo);
        uint256 newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);
        uint256 tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);
        // Do reverse order of fees charged in joinswap_ExternAmountIn, this way
        //     ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```
        //uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;
        uint256 zar = bmul(bsub(BONE, normalizedWeight), swapFee);
        tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));
        return tokenAmountIn;
      }
      /**********************************************************************************************
        // calcSingleOutGivenPoolIn                                                                  //
        // tAo = tokenAmountOut            /      /                                             \\\\   //
        // bO = tokenBalanceOut           /      // pS - (pAi * (1 - eF)) \\     /    1    \\      \\\\  //
        // pAi = poolAmountIn            | bO - || ----------------------- | ^ | --------- | * b0 || //
        // ps = poolSupply                \\      \\\\          pS           /     \\(wO / tW)/      //  //
        // wI = tokenWeightIn      tAo =   \\      \\                                             //   //
        // tW = totalWeight                    /     /      wO \\       \\                             //
        // sF = swapFee                    *  | 1 - |  1 - ---- | * sF  |                            //
        // eF = exitFee                        \\     \\      tW /       /                             //
        **********************************************************************************************/
      function calcSingleOutGivenPoolIn(
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 poolAmountIn,
        uint256 swapFee
      ) internal pure returns (uint256 tokenAmountOut) {
        uint256 normalizedWeight = bdiv(tokenWeightOut, totalWeight);
        // charge exit fee on the pool token side
        // pAiAfterExitFee = pAi*(1-exitFee)
        uint256 poolAmountInAfterExitFee = bmul(poolAmountIn, bsub(BONE, EXIT_FEE));
        uint256 newPoolSupply = bsub(poolSupply, poolAmountInAfterExitFee);
        uint256 poolRatio = bdiv(newPoolSupply, poolSupply);
        // newBalTo = poolRatio^(1/weightTo) * balTo;
        uint256 tokenOutRatio = bpow(poolRatio, bdiv(BONE, normalizedWeight));
        uint256 newTokenBalanceOut = bmul(tokenOutRatio, tokenBalanceOut);
        uint256 tokenAmountOutBeforeSwapFee = bsub(
          tokenBalanceOut,
          newTokenBalanceOut
        );
        // charge swap fee on the output token side
        //uint tAo = tAoBeforeSwapFee * (1 - (1-weightTo) * swapFee)
        uint256 zaz = bmul(bsub(BONE, normalizedWeight), swapFee);
        tokenAmountOut = bmul(tokenAmountOutBeforeSwapFee, bsub(BONE, zaz));
        return tokenAmountOut;
      }
      /**********************************************************************************************
        // calcPoolInGivenSingleOut                                                                  //
        // pAi = poolAmountIn               // /               tAo             \\\\     / wO \\     \\   //
        // bO = tokenBalanceOut            // | bO - -------------------------- |\\   | ---- |     \\  //
        // tAo = tokenAmountOut      pS - ||   \\     1 - ((1 - (tO / tW)) * sF)/  | ^ \\ tW /  * pS | //
        // ps = poolSupply                 \\\\ -----------------------------------/                /  //
        // wO = tokenWeightOut  pAi =       \\\\               bO                 /                /   //
        // tW = totalWeight           -------------------------------------------------------------  //
        // sF = swapFee                                        ( 1 - eF )                            //
        // eF = exitFee                                                                              //
        **********************************************************************************************/
      function calcPoolInGivenSingleOut(
        uint256 tokenBalanceOut,
        uint256 tokenWeightOut,
        uint256 poolSupply,
        uint256 totalWeight,
        uint256 tokenAmountOut,
        uint256 swapFee
      ) internal pure returns (uint256 poolAmountIn) {
        // charge swap fee on the output token side
        uint256 normalizedWeight = bdiv(tokenWeightOut, totalWeight);
        //uint tAoBeforeSwapFee = tAo / (1 - (1-weightTo) * swapFee) ;
        uint256 zoo = bsub(BONE, normalizedWeight);
        uint256 zar = bmul(zoo, swapFee);
        uint256 tokenAmountOutBeforeSwapFee = bdiv(tokenAmountOut, bsub(BONE, zar));
        uint256 newTokenBalanceOut = bsub(
          tokenBalanceOut,
          tokenAmountOutBeforeSwapFee
        );
        uint256 tokenOutRatio = bdiv(newTokenBalanceOut, tokenBalanceOut);
        //uint newPoolSupply = (ratioTo ^ weightTo) * poolSupply;
        uint256 poolRatio = bpow(tokenOutRatio, normalizedWeight);
        uint256 newPoolSupply = bmul(poolRatio, poolSupply);
        uint256 poolAmountInAfterExitFee = bsub(poolSupply, newPoolSupply);
        // charge exit fee on the pool token side
        // pAi = pAiAfterExitFee/(1-exitFee)
        poolAmountIn = bdiv(poolAmountInAfterExitFee, bsub(BONE, EXIT_FEE));
        return poolAmountIn;
      }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    import "./BConst.sol";
    /************************************************************************************************
    Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BNum.sol
    This source code has been modified from the original, which was copied from the github repository
    at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f.
    Subject to the GPL-3.0 license
    *************************************************************************************************/
    contract BNum is BConst {
      function btoi(uint256 a) internal pure returns (uint256) {
        return a / BONE;
      }
      function bfloor(uint256 a) internal pure returns (uint256) {
        return btoi(a) * BONE;
      }
      function badd(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "ERR_ADD_OVERFLOW");
        return c;
      }
      function bsub(uint256 a, uint256 b) internal pure returns (uint256) {
        (uint256 c, bool flag) = bsubSign(a, b);
        require(!flag, "ERR_SUB_UNDERFLOW");
        return c;
      }
      function bsubSign(uint256 a, uint256 b)
        internal
        pure
        returns (uint256, bool)
      {
        if (a >= b) {
          return (a - b, false);
        } else {
          return (b - a, true);
        }
      }
      function bmul(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c0 = a * b;
        require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
        uint256 c1 = c0 + (BONE / 2);
        require(c1 >= c0, "ERR_MUL_OVERFLOW");
        uint256 c2 = c1 / BONE;
        return c2;
      }
      function bdiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "ERR_DIV_ZERO");
        uint256 c0 = a * BONE;
        require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow
        uint256 c1 = c0 + (b / 2);
        require(c1 >= c0, "ERR_DIV_INTERNAL"); //  badd require
        uint256 c2 = c1 / b;
        return c2;
      }
      // DSMath.wpow
      function bpowi(uint256 a, uint256 n) internal pure returns (uint256) {
        uint256 z = n % 2 != 0 ? a : BONE;
        for (n /= 2; n != 0; n /= 2) {
          a = bmul(a, a);
          if (n % 2 != 0) {
            z = bmul(z, a);
          }
        }
        return z;
      }
      // Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
      // Use `bpowi` for `b^e` and `bpowK` for k iterations
      // of approximation of b^0.w
      function bpow(uint256 base, uint256 exp) internal pure returns (uint256) {
        require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW");
        require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH");
        uint256 whole = bfloor(exp);
        uint256 remain = bsub(exp, whole);
        uint256 wholePow = bpowi(base, btoi(whole));
        if (remain == 0) {
          return wholePow;
        }
        uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION);
        return bmul(wholePow, partialResult);
      }
      function bpowApprox(
        uint256 base,
        uint256 exp,
        uint256 precision
      ) internal pure returns (uint256) {
        // term 0:
        uint256 a = exp;
        (uint256 x, bool xneg) = bsubSign(base, BONE);
        uint256 term = BONE;
        uint256 sum = term;
        bool negative = false;
        // term(k) = numer / denom
        //         = (product(a - i - 1, i=1-->k) * x^k) / (k!)
        // each iteration, multiply previous term by (a-(k-1)) * x / k
        // continue until term is less than precision
        for (uint256 i = 1; term >= precision; i++) {
          uint256 bigK = i * BONE;
          (uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
          term = bmul(term, bmul(c, x));
          term = bdiv(term, bigK);
          if (term == 0) break;
          if (xneg) negative = !negative;
          if (cneg) negative = !negative;
          if (negative) {
            sum = bsub(sum, term);
          } else {
            sum = badd(sum, term);
          }
        }
        return sum;
      }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    import "./BNum.sol";
    /************************************************************************************************
    Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BToken.sol
    This source code has been modified from the original, which was copied from the github repository
    at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f.
    Subject to the GPL-3.0 license
    *************************************************************************************************/
    // Highly opinionated token implementation
    interface IERC20 {
      event Approval(address indexed src, address indexed dst, uint256 amt);
      event Transfer(address indexed src, address indexed dst, uint256 amt);
      function name() external view returns (string memory);
      function symbol() external view returns (string memory);
      function decimals() external view returns (uint8);
      function totalSupply() external view returns (uint256);
      function balanceOf(address whom) external view returns (uint256);
      function allowance(address src, address dst) external view returns (uint256);
      function approve(address dst, uint256 amt) external returns (bool);
      function transfer(address dst, uint256 amt) external returns (bool);
      function transferFrom(
        address src,
        address dst,
        uint256 amt
      ) external returns (bool);
    }
    contract BTokenBase is BNum {
      mapping(address => uint256) internal _balance;
      mapping(address => mapping(address => uint256)) internal _allowance;
      uint256 internal _totalSupply;
      event Approval(address indexed src, address indexed dst, uint256 amt);
      event Transfer(address indexed src, address indexed dst, uint256 amt);
      function _mint(uint256 amt) internal {
        _balance[address(this)] = badd(_balance[address(this)], amt);
        _totalSupply = badd(_totalSupply, amt);
        emit Transfer(address(0), address(this), amt);
      }
      function _burn(uint256 amt) internal {
        require(_balance[address(this)] >= amt, "ERR_INSUFFICIENT_BAL");
        _balance[address(this)] = bsub(_balance[address(this)], amt);
        _totalSupply = bsub(_totalSupply, amt);
        emit Transfer(address(this), address(0), amt);
      }
      function _move(
        address src,
        address dst,
        uint256 amt
      ) internal {
        require(_balance[src] >= amt, "ERR_INSUFFICIENT_BAL");
        _balance[src] = bsub(_balance[src], amt);
        _balance[dst] = badd(_balance[dst], amt);
        emit Transfer(src, dst, amt);
      }
      function _push(address to, uint256 amt) internal {
        _move(address(this), to, amt);
      }
      function _pull(address from, uint256 amt) internal {
        _move(from, address(this), amt);
      }
    }
    contract BToken is BTokenBase, IERC20 {
      uint8 private constant DECIMALS = 18;
      string private _name;
      string private _symbol;
      function _initializeToken(string memory name, string memory symbol) internal {
        require(
          bytes(_name).length == 0 &&
          bytes(name).length != 0 &&
          bytes(symbol).length != 0,
          "ERR_BTOKEN_INITIALIZED"
        );
        _name = name;
        _symbol = symbol;
      }
      function name()
        external
        override
        view
        returns (string memory)
      {
        return _name;
      }
      function symbol()
        external
        override
        view
        returns (string memory)
      {
        return _symbol;
      }
      function decimals()
        external
        override
        view
        returns (uint8)
      {
        return DECIMALS;
      }
      function allowance(address src, address dst)
        external
        override
        view
        returns (uint256)
      {
        return _allowance[src][dst];
      }
      function balanceOf(address whom) external override view returns (uint256) {
        return _balance[whom];
      }
      function totalSupply() public override view returns (uint256) {
        return _totalSupply;
      }
      function approve(address dst, uint256 amt) external override returns (bool) {
        _allowance[msg.sender][dst] = amt;
        emit Approval(msg.sender, dst, amt);
        return true;
      }
      function increaseApproval(address dst, uint256 amt) external returns (bool) {
        _allowance[msg.sender][dst] = badd(_allowance[msg.sender][dst], amt);
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
      }
      function decreaseApproval(address dst, uint256 amt) external returns (bool) {
        uint256 oldValue = _allowance[msg.sender][dst];
        if (amt > oldValue) {
          _allowance[msg.sender][dst] = 0;
        } else {
          _allowance[msg.sender][dst] = bsub(oldValue, amt);
        }
        emit Approval(msg.sender, dst, _allowance[msg.sender][dst]);
        return true;
      }
      function transfer(address dst, uint256 amt) external override returns (bool) {
        _move(msg.sender, dst, amt);
        return true;
      }
      function transferFrom(
        address src,
        address dst,
        uint256 amt
      ) external override returns (bool) {
        require(
          msg.sender == src || amt <= _allowance[src][msg.sender],
          "ERR_BTOKEN_BAD_CALLER"
        );
        _move(src, dst, amt);
        if (msg.sender != src && _allowance[src][msg.sender] != uint256(-1)) {
          _allowance[src][msg.sender] = bsub(_allowance[src][msg.sender], amt);
          emit Approval(msg.sender, dst, _allowance[src][msg.sender]);
        }
        return true;
      }
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    pragma experimental ABIEncoderV2;
    /* ========== Internal Inheritance ========== */
    import "./BToken.sol";
    import "./BMath.sol";
    /* ========== Internal Interfaces ========== */
    import "../interfaces/IIndexPool.sol";
    import "../interfaces/ICompLikeToken.sol";
    /************************************************************************************************
    Originally from https://github.com/balancer-labs/balancer-core/blob/master/contracts/BPool.sol
    This source code has been modified from the original, which was copied from the github repository
    at commit hash f4ed5d65362a8d6cec21662fb6eae233b0babc1f.
    Subject to the GPL-3.0 license
    *************************************************************************************************/
    contract SigmaIndexPoolV1 is BToken, BMath, IIndexPool {
    /* ==========  EVENTS  ========== */
      /** @dev Emitted when tokens are swapped. */
      event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256 tokenAmountIn,
        uint256 tokenAmountOut
      );
      /** @dev Emitted when underlying tokens are deposited for pool tokens. */
      event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint256 tokenAmountIn
      );
      /** @dev Emitted when pool tokens are burned for underlying. */
      event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint256 tokenAmountOut
      );
      /** @dev Emitted when a token's weight updates. */
      event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm);
      /** @dev Emitted when a token's desired weight is set. */
      event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm);
      /** @dev Emitted when a token is unbound from the pool. */
      event LOG_TOKEN_REMOVED(address token);
      /** @dev Emitted when a token is unbound from the pool. */
      event LOG_TOKEN_ADDED(
        address indexed token,
        uint256 desiredDenorm,
        uint256 minimumBalance
      );
      /** @dev Emitted when a token's minimum balance is updated. */
      event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance);
      /** @dev Emitted when a token reaches its minimum balance. */
      event LOG_TOKEN_READY(address indexed token);
      /** @dev Emitted when public trades are disabled. */
      event LOG_PUBLIC_SWAP_TOGGLED(bool enabled);
      /** @dev Emitted when the swap fee is updated. */
      event LOG_SWAP_FEE_UPDATED(uint256 swapFee);
    /* ==========  Modifiers  ========== */
      modifier _lock_ {
        require(!_mutex, "ERR_REENTRY");
        _mutex = true;
        _;
        _mutex = false;
      }
      modifier _viewlock_() {
        require(!_mutex, "ERR_REENTRY");
        _;
      }
      modifier _control_ {
        require(msg.sender == _controller, "ERR_NOT_CONTROLLER");
        _;
      }
      modifier _public_ {
        require(_publicSwap, "ERR_NOT_PUBLIC");
        _;
      }
    /* ==========  Storage  ========== */
      bool internal _mutex;
      // Account with CONTROL role. Able to modify the swap fee,
      // adjust token weights, bind and unbind tokens and lock
      // public swaps & joins.
      address internal _controller;
      // Contract that handles unbound tokens.
      TokenUnbindHandler internal _unbindHandler;
      // True if PUBLIC can call SWAP & JOIN functions
      bool internal _publicSwap;
      // `setSwapFee` requires CONTROL
      uint256 internal _swapFee;
      // Array of underlying tokens in the pool.
      address[] internal _tokens;
      // Internal records of the pool's underlying tokens
      mapping(address => Record) internal _records;
      // Total denormalized weight of the pool.
      uint256 internal _totalWeight;
      // Minimum balances for tokens which have been added without the
      // requisite initial balance.
      mapping(address => uint256) internal _minimumBalances;
      // Recipient for exit fees
      address internal _exitFeeRecipient;
    /* ==========  Controls  ========== */
      /**
       * @dev Sets the controller address and the token name & symbol.
       *
       * Note: This saves on storage costs for multi-step pool deployment.
       *
       * @param controller Controller of the pool
       * @param name Name of the pool token
       * @param symbol Symbol of the pool token
       */
      function configure(
        address controller,
        string calldata name,
        string calldata symbol
      ) external override {
        require(_controller == address(0), "ERR_CONFIGURED");
        require(controller != address(0), "ERR_NULL_ADDRESS");
        _controller = controller;
        // default fee is 2.5%
        _swapFee = BONE / 40;
        _initializeToken(name, symbol);
      }
      /**
       * @dev Sets up the initial assets for the pool.
       *
       * Note: `tokenProvider` must have approved the pool to transfer the
       * corresponding `balances` of `tokens`.
       *
       * @param tokens Underlying tokens to initialize the pool with
       * @param balances Initial balances to transfer
       * @param denorms Initial denormalized weights for the tokens
       * @param tokenProvider Address to transfer the balances from
       * @param unbindHandler Address that receives tokens removed from the pool
       * @param exitFeeRecipient Address that receives exit fees
       */
      function initialize(
        address[] calldata tokens,
        uint256[] calldata balances,
        uint96[] calldata denorms,
        address tokenProvider,
        address unbindHandler,
        address exitFeeRecipient
      )
        external
        override
        _control_
      {
        require(_tokens.length == 0, "ERR_INITIALIZED");
        uint256 len = tokens.length;
        require(len >= MIN_BOUND_TOKENS, "ERR_MIN_TOKENS");
        require(len <= MAX_BOUND_TOKENS, "ERR_MAX_TOKENS");
        require(balances.length == len && denorms.length == len, "ERR_ARR_LEN");
        uint256 totalWeight = 0;
        for (uint256 i = 0; i < len; i++) {
          address token = tokens[i];
          uint96 denorm = denorms[i];
          uint256 balance = balances[i];
          require(denorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT");
          require(denorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT");
          require(balance >= MIN_BALANCE, "ERR_MIN_BALANCE");
          _records[token] = Record({
            bound: true,
            ready: true,
            lastDenormUpdate: uint40(now),
            denorm: denorm,
            desiredDenorm: denorm,
            index: uint8(i),
            balance: balance
          });
          _tokens.push(token);
          totalWeight = badd(totalWeight, denorm);
          _pullUnderlying(token, tokenProvider, balance);
        }
        require(totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT");
        _totalWeight = totalWeight;
        _publicSwap = true;
        emit LOG_PUBLIC_SWAP_TOGGLED(true);
        _mintPoolShare(INIT_POOL_SUPPLY);
        _pushPoolShare(tokenProvider, INIT_POOL_SUPPLY);
        _unbindHandler = TokenUnbindHandler(unbindHandler);
        _exitFeeRecipient = exitFeeRecipient;
      }
      /**
       * @dev Set the swap fee.
       * Note: Swap fee must be between 0.0001% and 10%
       */
      function setSwapFee(uint256 swapFee) external override _control_ {
        require(swapFee >= MIN_FEE && swapFee <= MAX_FEE, "ERR_INVALID_FEE");
        _swapFee = swapFee;
        emit LOG_SWAP_FEE_UPDATED(swapFee);
      }
      /**
       * @dev Delegate a comp-like governance token to an address
       * specified by the controller.
       */
      function delegateCompLikeToken(address token, address delegatee)
        external
        override
        _control_
      {
        ICompLikeToken(token).delegate(delegatee);
      }
      /**
       * @dev Set the exit fee recipient address. Can only be called
       * by the current exit fee recipient.
       */
      function setExitFeeRecipient(address exitFeeRecipient) external override {
        require(msg.sender == _exitFeeRecipient, "ERR_NOT_FEE_RECIPIENT");
        _exitFeeRecipient = exitFeeRecipient;
      }
      /**
       * @dev Toggle public trading for the index pool.
       * This will enable or disable swaps and single-token joins and exits.
       */
      function setPublicSwap(bool enabled) external override _control_ {
        _publicSwap = enabled;
        emit LOG_PUBLIC_SWAP_TOGGLED(enabled);
      }
    /* ==========  Token Management Actions  ========== */
      /**
       * @dev Sets the desired weights for the pool tokens, which
       * will be adjusted over time as they are swapped.
       *
       * Note: This does not check for duplicate tokens or that the total
       * of the desired weights is equal to the target total weight (25).
       * Those assumptions should be met in the controller. Further, the
       * provided tokens should only include the tokens which are not set
       * for removal.
       */
      function reweighTokens(
        address[] calldata tokens,
        uint96[] calldata desiredDenorms
      )
        external
        override
        _lock_
        _control_
      {
        require(desiredDenorms.length == tokens.length, "ERR_ARR_LEN");
        for (uint256 i = 0; i < tokens.length; i++)
          _setDesiredDenorm(tokens[i], desiredDenorms[i]);
      }
      /**
       * @dev Update the underlying assets held by the pool and their associated
       * weights. Tokens which are not currently bound will be gradually added
       * as they are swapped in to reach the provided minimum balances, which must
       * be an amount of tokens worth the minimum weight of the total pool value.
       * If a currently bound token is not received in this call, the token's
       * desired weight will be set to 0.
       */
      function reindexTokens(
        address[] calldata tokens,
        uint96[] calldata desiredDenorms,
        uint256[] calldata minimumBalances
      )
        external
        override
        _lock_
        _control_
      {
        require(
          desiredDenorms.length == tokens.length && minimumBalances.length == tokens.length,
          "ERR_ARR_LEN"
        );
        // This size may not be the same as the input size, as it is possible
        // to temporarily exceed the index size while tokens are being phased in
        // or out.
        uint256 tLen = _tokens.length;
        bool[] memory receivedIndices = new bool[](tLen);
        // We need to read token records in two separate loops, so
        // write them to memory to avoid duplicate storage reads.
        Record[] memory records = new Record[](tokens.length);
        // Read all the records from storage and mark which of the existing tokens
        // were represented in the reindex call.
        for (uint256 i = 0; i < tokens.length; i++) {
          records[i] = _records[tokens[i]];
          if (records[i].bound) receivedIndices[records[i].index] = true;
        }
        // If any bound tokens were not sent in this call, set their desired weights to 0.
        for (uint256 i = 0; i < tLen; i++) {
          if (!receivedIndices[i]) {
            _setDesiredDenorm(_tokens[i], 0);
          }
        }
        for (uint256 i = 0; i < tokens.length; i++) {
          address token = tokens[i];
          // If an input weight is less than the minimum weight, use that instead.
          uint96 denorm = desiredDenorms[i];
          if (denorm < MIN_WEIGHT) denorm = uint96(MIN_WEIGHT);
          if (!records[i].bound) {
            // If the token is not bound, bind it.
            _bind(token, minimumBalances[i], denorm);
          } else {
            _setDesiredDenorm(token, denorm);
          }
        }
      }
      /**
       * @dev Updates the minimum balance for an uninitialized token.
       * This becomes useful if a token's external price significantly
       * rises after being bound, since the pool can not send a token
       * out until it reaches the minimum balance.
       */
      function setMinimumBalance(
        address token,
        uint256 minimumBalance
      )
        external
        override
        _control_
      {
        Record storage record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        require(!record.ready, "ERR_READY");
        _minimumBalances[token] = minimumBalance;
        emit LOG_MINIMUM_BALANCE_UPDATED(token, minimumBalance);
      }
    /* ==========  Liquidity Provider Actions  ========== */
      /**
       * @dev Mint new pool tokens by providing the proportional amount of each
       * underlying token's balance relative to the proportion of pool tokens minted.
       *
       * For any underlying tokens which are not initialized, the caller must provide
       * the proportional share of the minimum balance for the token rather than the
       * actual balance.
       *
       * @param poolAmountOut Amount of pool tokens to mint
       * @param maxAmountsIn Maximum amount of each token to pay in the same
       * order as the pool's _tokens list.
       */
      function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn)
        external
        override
        _lock_
        _public_
      {
        uint256 poolTotal = totalSupply();
        uint256 ratio = bdiv(poolAmountOut, poolTotal);
        require(ratio != 0, "ERR_MATH_APPROX");
        require(maxAmountsIn.length == _tokens.length, "ERR_ARR_LEN");
        for (uint256 i = 0; i < maxAmountsIn.length; i++) {
          address t = _tokens[i];
          (Record memory record, uint256 realBalance) = _getInputToken(t);
          uint256 tokenAmountIn = bmul(ratio, record.balance);
          require(tokenAmountIn != 0, "ERR_MATH_APPROX");
          require(tokenAmountIn <= maxAmountsIn[i], "ERR_LIMIT_IN");
          _updateInputToken(t, record, badd(realBalance, tokenAmountIn));
          emit LOG_JOIN(msg.sender, t, tokenAmountIn);
          _pullUnderlying(t, msg.sender, tokenAmountIn);
        }
        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
      }
      /**
       * @dev Pay `tokenAmountIn` of `tokenIn` to mint at least `minPoolAmountOut`
       * pool tokens.
       *
       * The pool implicitly swaps `(1- weightTokenIn) * tokenAmountIn` to the other
       * underlying tokens. Thus a swap fee is charged against the input tokens.
       *
       * @param tokenIn Token to send the pool
       * @param tokenAmountIn Exact amount of `tokenIn` to pay
       * @param minPoolAmountOut Minimum amount of pool tokens to mint
       * @return poolAmountOut - Amount of pool tokens minted
       */
      function joinswapExternAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        uint256 minPoolAmountOut
      )
        external
        override
        _lock_
        _public_
        returns (uint256/* poolAmountOut */)
      {
        (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn);
        require(tokenAmountIn != 0, "ERR_ZERO_IN");
        require(
          tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO),
          "ERR_MAX_IN_RATIO"
        );
        uint256 poolAmountOut = calcPoolOutGivenSingleIn(
          inRecord.balance,
          inRecord.denorm,
          _totalSupply,
          _totalWeight,
          tokenAmountIn,
          _swapFee
        );
        require(poolAmountOut >= minPoolAmountOut, "ERR_LIMIT_OUT");
        _updateInputToken(tokenIn, inRecord, badd(realInBalance, tokenAmountIn));
        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);
        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        return poolAmountOut;
      }
      /**
       * @dev Pay up to `maxAmountIn` of `tokenIn` to mint exactly `poolAmountOut`.
       *
       * The pool implicitly swaps `(1- weightTokenIn) * tokenAmountIn` to the other
       * underlying tokens. Thus a swap fee is charged against the input tokens.
       *
       * @param tokenIn Token to send the pool
       * @param poolAmountOut Exact amount of pool tokens to mint
       * @param maxAmountIn Maximum amount of `tokenIn` to pay
       * @return tokenAmountIn - Amount of `tokenIn` paid
       */
      function joinswapPoolAmountOut(
        address tokenIn,
        uint256 poolAmountOut,
        uint256 maxAmountIn
      )
        external
        override
        _lock_
        _public_
        returns (uint256/* tokenAmountIn */)
      {
        (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn);
        uint256 tokenAmountIn = calcSingleInGivenPoolOut(
          inRecord.balance,
          inRecord.denorm,
          _totalSupply,
          _totalWeight,
          poolAmountOut,
          _swapFee
        );
        require(tokenAmountIn != 0, "ERR_MATH_APPROX");
        require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN");
        require(
          tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO),
          "ERR_MAX_IN_RATIO"
        );
        _updateInputToken(tokenIn, inRecord, badd(realInBalance, tokenAmountIn));
        emit LOG_JOIN(msg.sender, tokenIn, tokenAmountIn);
        _mintPoolShare(poolAmountOut);
        _pushPoolShare(msg.sender, poolAmountOut);
        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        return tokenAmountIn;
      }
      /**
       * @dev Burns `poolAmountIn` pool tokens in exchange for the amounts of each
       * underlying token's balance proportional to the ratio of tokens burned to
       * total pool supply. The amount of each token transferred to the caller must
       * be greater than or equal to the associated minimum output amount from the
       * `minAmountsOut` array.
       *
       * @param poolAmountIn Exact amount of pool tokens to burn
       * @param minAmountsOut Minimum amount of each token to receive, in the same
       * order as the pool's _tokens list.
       */
      function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut)
        external
        override
        _lock_
      {
        require(minAmountsOut.length == _tokens.length, "ERR_ARR_LEN");
        uint256 poolTotal = totalSupply();
        uint256 exitFee = bmul(poolAmountIn, EXIT_FEE);
        uint256 pAiAfterExitFee = bsub(poolAmountIn, exitFee);
        uint256 ratio = bdiv(pAiAfterExitFee, poolTotal);
        require(ratio != 0, "ERR_MATH_APPROX");
        _pullPoolShare(msg.sender, poolAmountIn);
        _pushPoolShare(_exitFeeRecipient, exitFee);
        _burnPoolShare(pAiAfterExitFee);
        for (uint256 i = 0; i < minAmountsOut.length; i++) {
          address t = _tokens[i];
          Record memory record = _records[t];
          if (record.ready) {
            uint256 tokenAmountOut = bmul(ratio, record.balance);
            require(tokenAmountOut != 0, "ERR_MATH_APPROX");
            require(tokenAmountOut >= minAmountsOut[i], "ERR_LIMIT_OUT");
            _records[t].balance = bsub(record.balance, tokenAmountOut);
            emit LOG_EXIT(msg.sender, t, tokenAmountOut);
            _pushUnderlying(t, msg.sender, tokenAmountOut);
          } else {
            // If the token is not initialized, it can not exit the pool.
            require(minAmountsOut[i] == 0, "ERR_OUT_NOT_READY");
          }
        }
      }
      /**
       * @dev Burns `poolAmountIn` pool tokens in exchange for at least `minAmountOut`
       * of `tokenOut`. Returns the number of tokens sent to the caller.
       *
       * The pool implicitly burns the tokens for all underlying tokens and swaps them
       * to the desired output token. A swap fee is charged against the output tokens.
       *
       * @param tokenOut Token to receive
       * @param poolAmountIn Exact amount of pool tokens to burn
       * @param minAmountOut Minimum amount of `tokenOut` to receive
       * @return tokenAmountOut - Amount of `tokenOut` received
       */
      function exitswapPoolAmountIn(
        address tokenOut,
        uint256 poolAmountIn,
        uint256 minAmountOut
      )
        external
        override
        _lock_
        returns (uint256/* tokenAmountOut */)
      {
        Record memory outRecord = _getOutputToken(tokenOut);
        uint256 tokenAmountOut = calcSingleOutGivenPoolIn(
          outRecord.balance,
          outRecord.denorm,
          _totalSupply,
          _totalWeight,
          poolAmountIn,
          _swapFee
        );
        require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT");
        require(
          tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO),
          "ERR_MAX_OUT_RATIO"
        );
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        _records[tokenOut].balance = bsub(outRecord.balance, tokenAmountOut);
        _decreaseDenorm(outRecord, tokenOut);
        uint256 exitFee = bmul(poolAmountIn, EXIT_FEE);
        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);
        _pullPoolShare(msg.sender, poolAmountIn);
        _burnPoolShare(bsub(poolAmountIn, exitFee));
        _pushPoolShare(_exitFeeRecipient, exitFee);
        return tokenAmountOut;
      }
      /**
       * @dev Burn up to `maxPoolAmountIn` for exactly `tokenAmountOut` of `tokenOut`.
       * Returns the number of pool tokens burned.
       *
       * The pool implicitly burns the tokens for all underlying tokens and swaps them
       * to the desired output token. A swap fee is charged against the output tokens.
       *
       * @param tokenOut Token to receive
       * @param tokenAmountOut Exact amount of `tokenOut` to receive
       * @param maxPoolAmountIn Maximum amount of pool tokens to burn
       * @return poolAmountIn - Amount of pool tokens burned
       */
      function exitswapExternAmountOut(
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPoolAmountIn
      )
        external
        override
        _lock_
        returns (uint256/* poolAmountIn */)
      {
        Record memory outRecord = _getOutputToken(tokenOut);
        require(
          tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO),
          "ERR_MAX_OUT_RATIO"
        );
        uint256 poolAmountIn = calcPoolInGivenSingleOut(
          outRecord.balance,
          outRecord.denorm,
          _totalSupply,
          _totalWeight,
          tokenAmountOut,
          _swapFee
        );
        require(poolAmountIn != 0, "ERR_MATH_APPROX");
        require(poolAmountIn <= maxPoolAmountIn, "ERR_LIMIT_IN");
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        _records[tokenOut].balance = bsub(outRecord.balance, tokenAmountOut);
        _decreaseDenorm(outRecord, tokenOut);
        uint256 exitFee = bmul(poolAmountIn, EXIT_FEE);
        emit LOG_EXIT(msg.sender, tokenOut, tokenAmountOut);
        _pullPoolShare(msg.sender, poolAmountIn);
        _burnPoolShare(bsub(poolAmountIn, exitFee));
        _pushPoolShare(_exitFeeRecipient, exitFee);
        return poolAmountIn;
      }
    /* ==========  Other  ========== */
      /**
       * @dev Absorb any tokens that have been sent to the pool.
       * If the token is not bound, it will be sent to the unbound
       * token handler.
       */
      function gulp(address token) external override _lock_ {
        Record storage record = _records[token];
        uint256 balance = IERC20(token).balanceOf(address(this));
        if (record.bound) {
          if (!record.ready) {
            uint256 minimumBalance = _minimumBalances[token];
            if (balance >= minimumBalance) {
              _minimumBalances[token] = 0;
              record.ready = true;
              emit LOG_TOKEN_READY(token);
              uint256 additionalBalance = bsub(balance, minimumBalance);
              uint256 balRatio = bdiv(additionalBalance, minimumBalance);
              uint96 newDenorm = uint96(badd(MIN_WEIGHT, bmul(MIN_WEIGHT, balRatio)));
              record.denorm = newDenorm;
              record.lastDenormUpdate = uint40(now);
              _totalWeight = badd(_totalWeight, newDenorm);
              emit LOG_DENORM_UPDATED(token, record.denorm);
            }
          }
          _records[token].balance = balance;
        } else {
          _pushUnderlying(token, address(_unbindHandler), balance);
          _unbindHandler.handleUnbindToken(token, balance);
        }
      }
    /* ==========  Token Swaps  ========== */
      /**
       * @dev Execute a token swap with a specified amount of input
       * tokens and a minimum amount of output tokens.
       *
       * Note: Will revert if `tokenOut` is uninitialized.
       *
       * @param tokenIn Token to swap in
       * @param tokenAmountIn Exact amount of `tokenIn` to swap in
       * @param tokenOut Token to swap out
       * @param minAmountOut Minimum amount of `tokenOut` to receive
       * @param maxPrice Maximum ratio of input to output tokens
       * @return (tokenAmountOut, spotPriceAfter)
       */
      function swapExactAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        address tokenOut,
        uint256 minAmountOut,
        uint256 maxPrice
      )
        external
        override
        _lock_
        _public_
        returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */)
      {
        (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn);
        Record memory outRecord = _getOutputToken(tokenOut);
        require(
          tokenAmountIn <= bmul(inRecord.balance, MAX_IN_RATIO),
          "ERR_MAX_IN_RATIO"
        );
        uint256 spotPriceBefore = calcSpotPrice(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          _swapFee
        );
        require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE");
        uint256 tokenAmountOut = calcOutGivenIn(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          tokenAmountIn,
          _swapFee
        );
        require(tokenAmountOut >= minAmountOut, "ERR_LIMIT_OUT");
        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        realInBalance = badd(realInBalance, tokenAmountIn);
        _updateInputToken(tokenIn, inRecord, realInBalance);
        if (inRecord.ready) {
          inRecord.balance = realInBalance;
        }
        // Update the in-memory record for the spotPriceAfter calculation,
        // then update the storage record with the local balance.
        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);
        _records[tokenOut].balance = outRecord.balance;
        // If needed, update the output token's weight.
        _decreaseDenorm(outRecord, tokenOut);
        uint256 spotPriceAfter = calcSpotPrice(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          _swapFee
        );
        require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX_2");
        require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE");
        require(
          spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut),
          "ERR_MATH_APPROX"
        );
        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);
        return (tokenAmountOut, spotPriceAfter);
      }
      /**
       * @dev Trades at most `maxAmountIn` of `tokenIn` for exactly `tokenAmountOut`
       * of `tokenOut`.
       *
       * Returns the actual input amount and the new spot price after the swap,
       * which can not exceed `maxPrice`.
       *
       * @param tokenIn Token to swap in
       * @param maxAmountIn Maximum amount of `tokenIn` to pay
       * @param tokenOut Token to swap out
       * @param tokenAmountOut Exact amount of `tokenOut` to receive
       * @param maxPrice Maximum ratio of input to output tokens
       * @return (tokenAmountIn, spotPriceAfter)
       */
      function swapExactAmountOut(
        address tokenIn,
        uint256 maxAmountIn,
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPrice
      )
        external
        override
        _lock_
        _public_
        returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */)
      {
        (Record memory inRecord, uint256 realInBalance) = _getInputToken(tokenIn);
        Record memory outRecord = _getOutputToken(tokenOut);
        require(
          tokenAmountOut <= bmul(outRecord.balance, MAX_OUT_RATIO),
          "ERR_MAX_OUT_RATIO"
        );
        uint256 spotPriceBefore = calcSpotPrice(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          _swapFee
        );
        require(spotPriceBefore <= maxPrice, "ERR_BAD_LIMIT_PRICE");
        uint256 tokenAmountIn = calcInGivenOut(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          tokenAmountOut,
          _swapFee
        );
        require(tokenAmountIn <= maxAmountIn, "ERR_LIMIT_IN");
        _pullUnderlying(tokenIn, msg.sender, tokenAmountIn);
        _pushUnderlying(tokenOut, msg.sender, tokenAmountOut);
        // Update the balance and (if necessary) weight of the input token.
        realInBalance = badd(realInBalance, tokenAmountIn);
        _updateInputToken(tokenIn, inRecord, realInBalance);
        if (inRecord.ready) {
          inRecord.balance = realInBalance;
        }
        // Update the in-memory record for the spotPriceAfter calculation,
        // then update the storage record with the local balance.
        outRecord.balance = bsub(outRecord.balance, tokenAmountOut);
        _records[tokenOut].balance = outRecord.balance;
        // If needed, update the output token's weight.
        _decreaseDenorm(outRecord, tokenOut);
        uint256 spotPriceAfter = calcSpotPrice(
          inRecord.balance,
          inRecord.denorm,
          outRecord.balance,
          outRecord.denorm,
          _swapFee
        );
        require(spotPriceAfter >= spotPriceBefore, "ERR_MATH_APPROX");
        require(spotPriceAfter <= maxPrice, "ERR_LIMIT_PRICE");
        require(
          spotPriceBefore <= bdiv(tokenAmountIn, tokenAmountOut),
          "ERR_MATH_APPROX"
        );
        emit LOG_SWAP(msg.sender, tokenIn, tokenOut, tokenAmountIn, tokenAmountOut);
        return (tokenAmountIn, spotPriceAfter);
      }
    /* ==========  Config Queries  ========== */
      /**
       * @dev Check if swapping tokens and joining the pool is allowed.
       */
      function isPublicSwap() external view override returns (bool) {
        return _publicSwap;
      }
      function getSwapFee() external view override _viewlock_ returns (uint256/* swapFee */) {
        return _swapFee;
      }
      /**
       * @dev Returns the controller address.
       */
      function getController() external view override returns (address) {
        return _controller;
      }
      /**
       * @dev Returns the exit fee recipient address.
       */
      function getExitFeeRecipient() external view override returns (address) {
        return _exitFeeRecipient;
      }
    /* ==========  Token Queries  ========== */
      /**
       * @dev Check if a token is bound to the pool.
       */
      function isBound(address t) external view override returns (bool) {
        return _records[t].bound;
      }
      /**
       * @dev Get the number of tokens bound to the pool.
       */
      function getNumTokens() external view override returns (uint256) {
        return _tokens.length;
      }
      /**
       * @dev Get all bound tokens.
       */
      function getCurrentTokens()
        external
        view
        override
        _viewlock_
        returns (address[] memory tokens)
      {
        tokens = _tokens;
      }
      /**
       * @dev Returns the list of tokens which have a desired weight above 0.
       * Tokens with a desired weight of 0 are set to be phased out of the pool.
       */
      function getCurrentDesiredTokens()
        external
        view
        override
        _viewlock_
        returns (address[] memory tokens)
      {
        address[] memory tempTokens = _tokens;
        tokens = new address[](tempTokens.length);
        uint256 usedIndex = 0;
        for (uint256 i = 0; i < tokens.length; i++) {
          address token = tempTokens[i];
          if (_records[token].desiredDenorm > 0) {
            tokens[usedIndex++] = token;
          }
        }
        assembly { mstore(tokens, usedIndex) }
      }
      /**
       * @dev Returns the denormalized weight of a bound token.
       */
      function getDenormalizedWeight(address token)
        external
        view
        override
        _viewlock_
        returns (uint256/* denorm */)
      {
        require(_records[token].bound, "ERR_NOT_BOUND");
        return _records[token].denorm;
      }
      /**
       * @dev Returns the record for a token bound to the pool.
       */
      function getTokenRecord(address token)
        external
        view
        override
        _viewlock_
        returns (Record memory record)
      {
        record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
      }
      /**
       * @dev Finds the first token which is both initialized and has a
       * desired weight above 0, then returns the address of that token
       * and the extrapolated value of the pool in terms of that token.
       *
       * The value is extrapolated by multiplying the token's
       * balance by the reciprocal of its normalized weight.
       * @return (token, extrapolatedValue)
       */
      function extrapolatePoolValueFromToken()
        external
        view
        override
        _viewlock_
        returns (address/* token */, uint256/* extrapolatedValue */)
      {
        address token;
        uint256 extrapolatedValue;
        uint256 len = _tokens.length;
        for (uint256 i = 0; i < len; i++) {
          token = _tokens[i];
          Record storage record = _records[token];
          if (record.ready && record.desiredDenorm > 0) {
            extrapolatedValue = bmul(
              record.balance,
              bdiv(_totalWeight, record.denorm)
            );
            break;
          }
        }
        require(extrapolatedValue > 0, "ERR_NONE_READY");
        return (token, extrapolatedValue);
      }
      /**
       * @dev Get the total denormalized weight of the pool.
       */
      function getTotalDenormalizedWeight()
        external
        view
        override
        _viewlock_
        returns (uint256)
      {
        return _totalWeight;
      }
      /**
       * @dev Returns the stored balance of a bound token.
       */
      function getBalance(address token) external view override _viewlock_ returns (uint256) {
        Record storage record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        return record.balance;
      }
      /**
       * @dev Get the minimum balance of an uninitialized token.
       * Note: Throws if the token is initialized.
       */
      function getMinimumBalance(address token) external view override _viewlock_ returns (uint256) {
        Record memory record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        require(!record.ready, "ERR_READY");
        return _minimumBalances[token];
      }
      /**
       * @dev Returns the balance of a token which is used in price
       * calculations. If the token is initialized, this is the
       * stored balance; if not, this is the minimum balance.
       */
      function getUsedBalance(address token) external view override _viewlock_ returns (uint256) {
        Record memory record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        if (!record.ready) {
          return _minimumBalances[token];
        }
        return record.balance;
      }
    /* ==========  Price Queries  ========== */
      /**
       * @dev Returns the spot price for `tokenOut` in terms of `tokenIn`.
       */
      function getSpotPrice(address tokenIn, address tokenOut)
        external
        view
        override
        _viewlock_
        returns (uint256)
      {
        (Record memory inRecord,) = _getInputToken(tokenIn);
        Record memory outRecord = _getOutputToken(tokenOut);
        return
          calcSpotPrice(
            inRecord.balance,
            inRecord.denorm,
            outRecord.balance,
            outRecord.denorm,
            _swapFee
          );
      }
    /* ==========  Pool Share Internal Functions  ========== */
      function _pullPoolShare(address from, uint256 amount) internal {
        _pull(from, amount);
      }
      function _pushPoolShare(address to, uint256 amount) internal {
        _push(to, amount);
      }
      function _mintPoolShare(uint256 amount) internal {
        _mint(amount);
      }
      function _burnPoolShare(uint256 amount) internal {
        _burn(amount);
      }
    /* ==========  Underlying Token Internal Functions  ========== */
      // 'Underlying' token-manipulation functions make external calls but are NOT locked
      // You must `_lock_` or otherwise ensure reentry-safety
      function _pullUnderlying(
        address erc20,
        address from,
        uint256 amount
      ) internal {
        (bool success, bytes memory data) = erc20.call(
          abi.encodeWithSelector(
            IERC20.transferFrom.selector,
            from,
            address(this),
            amount
          )
        );
        require(
          success && (data.length == 0 || abi.decode(data, (bool))),
          "ERR_ERC20_FALSE"
        );
      }
      function _pushUnderlying(
        address erc20,
        address to,
        uint256 amount
      ) internal {
        (bool success, bytes memory data) = erc20.call(
          abi.encodeWithSelector(
            IERC20.transfer.selector,
            to,
            amount
          )
        );
        require(
          success && (data.length == 0 || abi.decode(data, (bool))),
          "ERR_ERC20_FALSE"
        );
      }
    /* ==========  Token Management Internal Functions  ========== */
      /**
       * @dev Bind a token by address without actually depositing a balance.
       * The token will be unable to be swapped out until it reaches the minimum balance.
       * Note: Token must not already be bound.
       * Note: `minimumBalance` should represent an amount of the token which is worth
       * the portion of the current pool value represented by the minimum weight.
       * @param token Address of the token to bind
       * @param minimumBalance minimum balance to reach before the token can be swapped out
       * @param desiredDenorm Desired weight for the token.
       */
      function _bind(
        address token,
        uint256 minimumBalance,
        uint96 desiredDenorm
      ) internal {
        require(!_records[token].bound, "ERR_IS_BOUND");
        require(desiredDenorm >= MIN_WEIGHT, "ERR_MIN_WEIGHT");
        require(desiredDenorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT");
        require(minimumBalance >= MIN_BALANCE, "ERR_MIN_BALANCE");
        _records[token] = Record({
          bound: true,
          ready: false,
          lastDenormUpdate: 0,
          denorm: 0,
          desiredDenorm: desiredDenorm,
          index: uint8(_tokens.length),
          balance: 0
        });
        _tokens.push(token);
        _minimumBalances[token] = minimumBalance;
        emit LOG_TOKEN_ADDED(token, desiredDenorm, minimumBalance);
      }
      /**
       * @dev Remove a token from the pool.
       * Replaces the address in the tokens array with the last address,
       * then removes it from the array.
       * Note: This should only be called after the total weight has been adjusted.
       * Note: Must be called in a function with:
       * - _lock_ modifier to prevent reentrance
       * - requirement that the token is bound
       */
      function _unbind(address token) internal {
        Record memory record = _records[token];
        uint256 tokenBalance = record.balance;
        // Swap the token-to-unbind with the last token,
        // then delete the last token
        uint256 index = record.index;
        uint256 last = _tokens.length - 1;
        // Only swap the token with the last token if it is not
        // already at the end of the array.
        if (index != last) {
          _tokens[index] = _tokens[last];
          _records[_tokens[index]].index = uint8(index);
        }
        _tokens.pop();
        _records[token] = Record({
          bound: false,
          ready: false,
          lastDenormUpdate: 0,
          denorm: 0,
          desiredDenorm: 0,
          index: 0,
          balance: 0
        });
        // transfer any remaining tokens out
        _pushUnderlying(token, address(_unbindHandler), tokenBalance);
        _unbindHandler.handleUnbindToken(token, tokenBalance);
        emit LOG_TOKEN_REMOVED(token);
      }
      function _setDesiredDenorm(address token, uint96 desiredDenorm) internal {
        Record storage record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        // If the desired weight is 0, this will trigger a gradual unbinding of the token.
        // Therefore the weight only needs to be above the minimum weight if it isn't 0.
        require(
          desiredDenorm >= MIN_WEIGHT || desiredDenorm == 0,
          "ERR_MIN_WEIGHT"
        );
        require(desiredDenorm <= MAX_WEIGHT, "ERR_MAX_WEIGHT");
        record.desiredDenorm = desiredDenorm;
        emit LOG_DESIRED_DENORM_SET(token, desiredDenorm);
      }
      function _increaseDenorm(Record memory record, address token) internal {
        // If the weight does not need to increase or the token is not
        // initialized, don't do anything.
        if (
          record.denorm >= record.desiredDenorm ||
          !record.ready ||
          now - record.lastDenormUpdate < WEIGHT_UPDATE_DELAY
        ) return;
        uint96 oldWeight = record.denorm;
        uint96 denorm = record.desiredDenorm;
        uint256 maxDiff = bmul(oldWeight, WEIGHT_CHANGE_PCT);
        uint256 diff = bsub(denorm, oldWeight);
        if (diff > maxDiff) {
          denorm = uint96(badd(oldWeight, maxDiff));
          diff = maxDiff;
        }
        _totalWeight = badd(_totalWeight, diff);
        require(_totalWeight <= MAX_TOTAL_WEIGHT, "ERR_MAX_TOTAL_WEIGHT");
        // Update the in-memory denorm value for spot-price computations.
        record.denorm = denorm;
        // Update the storage record
        _records[token].denorm = denorm;
        _records[token].lastDenormUpdate = uint40(now);
        emit LOG_DENORM_UPDATED(token, denorm);
      }
      function _decreaseDenorm(Record memory record, address token) internal {
        // If the weight does not need to decrease, don't do anything.
        if (
          record.denorm <= record.desiredDenorm ||
          !record.ready ||
          now - record.lastDenormUpdate < WEIGHT_UPDATE_DELAY
        ) return;
        uint96 oldWeight = record.denorm;
        uint96 denorm = record.desiredDenorm;
        uint256 maxDiff = bmul(oldWeight, WEIGHT_CHANGE_PCT);
        uint256 diff = bsub(oldWeight, denorm);
        if (diff > maxDiff) {
          denorm = uint96(bsub(oldWeight, maxDiff));
          diff = maxDiff;
        }
        if (denorm <= MIN_WEIGHT) {
          denorm = 0;
          _totalWeight = bsub(_totalWeight, denorm);
          // Because this is removing the token from the pool, the
          // in-memory denorm value is irrelevant, as it is only used
          // to calculate the new spot price, but the spot price calc
          // will throw if it is passed 0 for the denorm.
          _unbind(token);
        } else {
          _totalWeight = bsub(_totalWeight, diff);
          // Update the in-memory denorm value for spot-price computations.
          record.denorm = denorm;
          // Update the stored denorm value
          _records[token].denorm = denorm;
          _records[token].lastDenormUpdate = uint40(now);
          emit LOG_DENORM_UPDATED(token, denorm);
        }
      }
      /**
       * @dev Handles weight changes and initialization of an
       * input token.
       *
       * If the token is not initialized and the new balance is
       * still below the minimum, this will not do anything.
       *
       * If the token is not initialized but the new balance will
       * bring the token above the minimum balance, this will
       * mark the token as initialized, remove the minimum
       * balance and set the weight to the minimum weight plus
       * 1%.
       *
       *
       * @param token Address of the input token
       * @param record Token record with minimums applied to the balance
       * and weight if the token was uninitialized.
       */
      function _updateInputToken(
        address token,
        Record memory record,
        uint256 realBalance
      )
        internal
      {
        if (!record.ready) {
          // Check if the minimum balance has been reached
          if (realBalance >= record.balance) {
            // Remove the minimum balance record
            _minimumBalances[token] = 0;
            // Mark the token as initialized
            _records[token].ready = true;
            record.ready = true;
            emit LOG_TOKEN_READY(token);
            // Set the initial denorm value to the minimum weight times one plus
            // the ratio of the increase in balance over the minimum to the minimum
            // balance.
            // weight = (1 + ((bal - min_bal) / min_bal)) * min_weight
            uint256 additionalBalance = bsub(realBalance, record.balance);
            uint256 balRatio = bdiv(additionalBalance, record.balance);
            record.denorm = uint96(badd(MIN_WEIGHT, bmul(MIN_WEIGHT, balRatio)));
            _records[token].denorm = record.denorm;
            _records[token].lastDenormUpdate = uint40(now);
            _totalWeight = badd(_totalWeight, record.denorm);
            emit LOG_DENORM_UPDATED(token, record.denorm);
          } else {
            uint256 realToMinRatio = bdiv(
              bsub(record.balance, realBalance),
              record.balance
            );
            uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio);
            record.denorm = uint96(badd(MIN_WEIGHT, weightPremium));
          }
          // If the token is still not ready, do not adjust the weight.
        } else {
          // If the token is already initialized, update the weight (if any adjustment
          // is needed).
          _increaseDenorm(record, token);
        }
        // Regardless of whether the token is initialized, store the actual new balance.
        _records[token].balance = realBalance;
      }
    /* ==========  Token Query Internal Functions  ========== */
      /**
       * @dev Get the record for a token which is being swapped in.
       * The token must be bound to the pool. If the token is not
       * initialized (meaning it does not have the minimum balance)
       * this function will return the actual balance of the token
       * which the pool holds, but set the record's balance and weight
       * to the token's minimum balance and the pool's minimum weight.
       * This allows the token swap to be priced correctly even if the
       * pool does not own any of the tokens.
       */
      function _getInputToken(address token)
        internal
        view
        returns (Record memory record, uint256 realBalance)
      {
        record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        realBalance = record.balance;
        // If the input token is not initialized, we use the minimum
        // initial weight and minimum initial balance instead of the
        // real values for price and output calculations.
        if (!record.ready) {
          record.balance = _minimumBalances[token];
          uint256 realToMinRatio = bdiv(
            bsub(record.balance, realBalance),
            record.balance
          );
          uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio);
          record.denorm = uint96(badd(MIN_WEIGHT, weightPremium));
        }
      }
      function _getOutputToken(address token)
        internal
        view
        returns (Record memory record)
      {
        record = _records[token];
        require(record.bound, "ERR_NOT_BOUND");
        // Tokens which have not reached their minimum balance can not be
        // swapped out.
        require(record.ready, "ERR_OUT_NOT_READY");
      }
    }
    interface TokenUnbindHandler {
      /**
       * @dev Receive `amount` of `token` from the pool.
       */
      function handleUnbindToken(address token, uint256 amount) external;
    }
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.6.0;
    pragma experimental ABIEncoderV2;
    interface IIndexPool {
      /**
       * @dev Token record data structure
       * @param bound is token bound to pool
       * @param ready has token been initialized
       * @param lastDenormUpdate timestamp of last denorm change
       * @param denorm denormalized weight
       * @param desiredDenorm desired denormalized weight (used for incremental changes)
       * @param index index of address in tokens array
       * @param balance token balance
       */
      struct Record {
        bool bound;
        bool ready;
        uint40 lastDenormUpdate;
        uint96 denorm;
        uint96 desiredDenorm;
        uint8 index;
        uint256 balance;
      }
      event LOG_SWAP(
        address indexed caller,
        address indexed tokenIn,
        address indexed tokenOut,
        uint256 tokenAmountIn,
        uint256 tokenAmountOut
      );
      event LOG_JOIN(
        address indexed caller,
        address indexed tokenIn,
        uint256 tokenAmountIn
      );
      event LOG_EXIT(
        address indexed caller,
        address indexed tokenOut,
        uint256 tokenAmountOut
      );
      event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm);
      event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm);
      event LOG_TOKEN_REMOVED(address token);
      event LOG_TOKEN_ADDED(
        address indexed token,
        uint256 desiredDenorm,
        uint256 minimumBalance
      );
      event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance);
      event LOG_TOKEN_READY(address indexed token);
      event LOG_PUBLIC_SWAP_TOGGLED(bool enabled);
      event LOG_MAX_TOKENS_UPDATED(uint256 maxPoolTokens);
      event LOG_SWAP_FEE_UPDATED(uint256 swapFee);
      function configure(
        address controller,
        string calldata name,
        string calldata symbol
      ) external;
      function initialize(
        address[] calldata tokens,
        uint256[] calldata balances,
        uint96[] calldata denorms,
        address tokenProvider,
        address unbindHandler,
        address exitFeeRecipient
      ) external;
      function setSwapFee(uint256 swapFee) external;
      function delegateCompLikeToken(address token, address delegatee) external;
      function setExitFeeRecipient(address) external;
      function setPublicSwap(bool enabled) external;
      function reweighTokens(
        address[] calldata tokens,
        uint96[] calldata desiredDenorms
      ) external;
      function reindexTokens(
        address[] calldata tokens,
        uint96[] calldata desiredDenorms,
        uint256[] calldata minimumBalances
      ) external;
      function setMinimumBalance(address token, uint256 minimumBalance) external;
      function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external;
      function joinswapExternAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        uint256 minPoolAmountOut
      ) external returns (uint256/* poolAmountOut */);
      function joinswapPoolAmountOut(
        address tokenIn,
        uint256 poolAmountOut,
        uint256 maxAmountIn
      ) external returns (uint256/* tokenAmountIn */);
      function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external;
      function exitswapPoolAmountIn(
        address tokenOut,
        uint256 poolAmountIn,
        uint256 minAmountOut
      )
        external returns (uint256/* tokenAmountOut */);
      function exitswapExternAmountOut(
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPoolAmountIn
      ) external returns (uint256/* poolAmountIn */);
      function gulp(address token) external;
      function swapExactAmountIn(
        address tokenIn,
        uint256 tokenAmountIn,
        address tokenOut,
        uint256 minAmountOut,
        uint256 maxPrice
      ) external returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */);
      function swapExactAmountOut(
        address tokenIn,
        uint256 maxAmountIn,
        address tokenOut,
        uint256 tokenAmountOut,
        uint256 maxPrice
      ) external returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */);
      function isPublicSwap() external view returns (bool);
      function getSwapFee() external view returns (uint256/* swapFee */);
      function getController() external view returns (address);
      function getExitFeeRecipient() external view returns (address);
      function isBound(address t) external view returns (bool);
      function getNumTokens() external view returns (uint256);
      function getCurrentTokens() external view returns (address[] memory tokens);
      function getCurrentDesiredTokens() external view returns (address[] memory tokens);
      function getDenormalizedWeight(address token) external view returns (uint256/* denorm */);
      function getTokenRecord(address token) external view returns (Record memory record);
      function extrapolatePoolValueFromToken() external view returns (address/* token */, uint256/* extrapolatedValue */);
      function getTotalDenormalizedWeight() external view returns (uint256);
      function getBalance(address token) external view returns (uint256);
      function getMinimumBalance(address token) external view returns (uint256);
      function getUsedBalance(address token) external view returns (uint256);
      function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.6.0;
    interface ICompLikeToken {
      function delegate(address delegatee) external;
    }