ETH Price: $2,480.27 (-1.15%)

Transaction Decoder

Block:
10493291 at Jul-20-2020 12:52:03 AM +UTC
Transaction Fee:
0.0077260892845119 ETH $19.16
Gas Used:
200,931 Gas / 38.4514549 Gwei

Emitted Events:

106 SetToken.Transfer( from=0x0000000000000000000000000000000000000000, to=Vault, value=1173798000000000000 )
107 Core.SetIssued( _setAddress=SetToken, _quantity=1173798000000000000 )
108 RebalancingSetTokenV3.RebalanceSettled( feeRecipient=0x0000000000000000000000000000000000000000, feeQuantity=0, feePercentage=0, rebalanceIndex=1, issueQuantity=1173798000000000000, unitShares=106805 )

Account State Difference:

  Address   Before After State Difference Code
0x40c3AB8F...3172f10DF
(Spark Pool)
54.69502337670090862 Eth54.70274946598542052 Eth0.0077260892845119
0x5B67871C...670D986Dc
(Set: Vault)
0x69Bdb276...E593ae8E3
(Set: Deployer)
1.361664656966924992 Eth
Nonce: 7250
1.353938567682413092 Eth
Nonce: 7251
0.0077260892845119
0x7510D6fa...a7f5049d4
0xf4501292...e4eeA02Bd
0xf55186CC...427a120C8

Execution Trace

RebalancingSetTokenV3.CALL( )
  • SetToken.STATICCALL( )
  • SetToken.STATICCALL( )
  • SetToken.STATICCALL( )
  • Vault.getOwnerBalance( _token=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4 ) => ( 117380709 )
  • Vault.getOwnerBalance( _token=0x39AA39c021dfbaE8faC545936693aC917d5E7563, _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4 ) => ( 462045612415578 )
  • Core.issueInVault( _set=0xf4501292c7eD95f6D9C2C9CDE1721bbe4eeA02Bd, _quantity=1173798000000000000 )
    • 0xdc733ec262f32882f7c05525cc2d09f2c04d86ac.49468457( )
      • SetToken.STATICCALL( )
      • SetToken.STATICCALL( )
      • SetToken.STATICCALL( )
      • SetToken.STATICCALL( )
      • CoreIssuanceLibrary.calculateRequiredComponentQuantities( _componentUnits=[100, 393632811], _naturalUnit=1000000000000, _quantity=1173798000000000000 ) => ( [117379800, 462045406286178] )
      • CoreIssuanceLibrary.calculateDepositAndDecrementQuantities( _components=[0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 0x39AA39c021dfbaE8faC545936693aC917d5E7563], _componentQuantities=[117379800, 462045406286178], _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4, _vault=0x5B67871C3a857dE81A1ca0f9F7945e5670D986Dc ) => ( [117379800, 462045406286178], [0, 0] )
        • Vault.getOwnerBalance( _token=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4 ) => ( 117380709 )
        • Vault.getOwnerBalance( _token=0x39AA39c021dfbaE8faC545936693aC917d5E7563, _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4 ) => ( 462045612415578 )
        • Vault.batchDecrementTokenOwner( _tokens=[0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 0x39AA39c021dfbaE8faC545936693aC917d5E7563], _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4, _quantities=[117379800, 462045406286178] )
        • TransferProxy.batchTransfer( _tokens=[0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 0x39AA39c021dfbaE8faC545936693aC917d5E7563], _quantities=[0, 0], _from=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4, _to=0x5B67871C3a857dE81A1ca0f9F7945e5670D986Dc )
        • Vault.batchIncrementTokenOwner( _tokens=[0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599, 0x39AA39c021dfbaE8faC545936693aC917d5E7563], _owner=0xf4501292c7eD95f6D9C2C9CDE1721bbe4eeA02Bd, _quantities=[117379800, 462045406286178] )
        • SetToken.mint( _issuer=0x5B67871C3a857dE81A1ca0f9F7945e5670D986Dc, _quantity=1173798000000000000 )
          • SetTokenFactory.CALL( )
          • Vault.incrementTokenOwner( _token=0xf4501292c7eD95f6D9C2C9CDE1721bbe4eeA02Bd, _owner=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4, _quantity=1173798000000000000 )
          • LinearAuctionLiquidator.CALL( )
            • Core.validSets( _set=0x7510D6fac98A6eCa2DB7c9357619715a7f5049d4 ) => ( True )
              File 1 of 8: RebalancingSetTokenV3
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title ERC20 interface
               * @dev see https://eips.ethereum.org/EIPS/eip-20
               */
              interface IERC20 {
                  function transfer(address to, uint256 value) external returns (bool);
              
                  function approve(address spender, uint256 value) external returns (bool);
              
                  function transferFrom(address from, address to, uint256 value) external returns (bool);
              
                  function totalSupply() external view returns (uint256);
              
                  function balanceOf(address who) external view returns (uint256);
              
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
              
              pragma solidity ^0.5.2;
              
              
              
              /**
               * @title Standard ERC20 token
               *
               * @dev Implementation of the basic standard token.
               * https://eips.ethereum.org/EIPS/eip-20
               * Originally based on code by FirstBlood:
               * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
               *
               * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
               * all accounts just by listening to said events. Note that this isn't required by the specification, and other
               * compliant implementations may not do it.
               */
              contract ERC20 is IERC20 {
                  using SafeMath for uint256;
              
                  mapping (address => uint256) private _balances;
              
                  mapping (address => mapping (address => uint256)) private _allowed;
              
                  uint256 private _totalSupply;
              
                  /**
                   * @dev Total number of tokens in existence
                   */
                  function totalSupply() public view returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev Gets the balance of the specified address.
                   * @param owner The address to query the balance of.
                   * @return A uint256 representing the amount owned by the passed address.
                   */
                  function balanceOf(address owner) public view returns (uint256) {
                      return _balances[owner];
                  }
              
                  /**
                   * @dev Function to check the amount of tokens that an owner allowed to a spender.
                   * @param owner address The address which owns the funds.
                   * @param spender address The address which will spend the funds.
                   * @return A uint256 specifying the amount of tokens still available for the spender.
                   */
                  function allowance(address owner, address spender) public view returns (uint256) {
                      return _allowed[owner][spender];
                  }
              
                  /**
                   * @dev Transfer token to a specified address
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function transfer(address to, uint256 value) public returns (bool) {
                      _transfer(msg.sender, to, value);
                      return true;
                  }
              
                  /**
                   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                   * Beware that changing an allowance with this method brings the risk that someone may use both the old
                   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
                   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to be spent.
                   */
                  function approve(address spender, uint256 value) public returns (bool) {
                      _approve(msg.sender, spender, value);
                      return true;
                  }
              
                  /**
                   * @dev Transfer tokens from one address to another.
                   * Note that while this function emits an Approval event, this is not required as per the specification,
                   * and other compliant implementations may not emit the event.
                   * @param from address The address which you want to send tokens from
                   * @param to address The address which you want to transfer to
                   * @param value uint256 the amount of tokens to be transferred
                   */
                  function transferFrom(address from, address to, uint256 value) public returns (bool) {
                      _transfer(from, to, value);
                      _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
                      return true;
                  }
              
                  /**
                   * @dev Increase the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To increment
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param addedValue The amount of tokens to increase the allowance by.
                   */
                  function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
                      return true;
                  }
              
                  /**
                   * @dev Decrease the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To decrement
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param subtractedValue The amount of tokens to decrease the allowance by.
                   */
                  function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
                      return true;
                  }
              
                  /**
                   * @dev Transfer token for a specified addresses
                   * @param from The address to transfer from.
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function _transfer(address from, address to, uint256 value) internal {
                      require(to != address(0));
              
                      _balances[from] = _balances[from].sub(value);
                      _balances[to] = _balances[to].add(value);
                      emit Transfer(from, to, value);
                  }
              
                  /**
                   * @dev Internal function that mints an amount of the token and assigns it to
                   * an account. This encapsulates the modification of balances such that the
                   * proper events are emitted.
                   * @param account The account that will receive the created tokens.
                   * @param value The amount that will be created.
                   */
                  function _mint(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.add(value);
                      _balances[account] = _balances[account].add(value);
                      emit Transfer(address(0), account, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account.
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burn(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.sub(value);
                      _balances[account] = _balances[account].sub(value);
                      emit Transfer(account, address(0), value);
                  }
              
                  /**
                   * @dev Approve an address to spend another addresses' tokens.
                   * @param owner The address that owns the tokens.
                   * @param spender The address that will spend the tokens.
                   * @param value The number of tokens that can be spent.
                   */
                  function _approve(address owner, address spender, uint256 value) internal {
                      require(spender != address(0));
                      require(owner != address(0));
              
                      _allowed[owner][spender] = value;
                      emit Approval(owner, spender, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account, deducting from the sender's allowance for said account. Uses the
                   * internal burn function.
                   * Emits an Approval event (reflecting the reduced allowance).
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burnFrom(address account, uint256 value) internal {
                      _burn(account, value);
                      _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  uint256 public constant SCALE_FACTOR = 10 ** 18;
                  uint256 public constant MAX_UINT_256 = 2 ** 256 - 1;
              
                  /**
                   * Returns scale factor equal to 10 ** 18
                   *
                   * @return  10 ** 18
                   */
                  function scaleFactor()
                      internal
                      pure
                      returns (uint256)
                  {
                      return SCALE_FACTOR;
                  }
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return MAX_UINT_256;
                  }
              
                  /**
                   * Increases a value by the scale factor to allow for additional precision
                   * during mathematical operations
                   */
                  function scale(
                      uint256 a
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      return a.mul(SCALE_FACTOR);
                  }
              
                  /**
                   * Divides a value by the scale factor to allow for additional precision
                   * during mathematical operations
                  */
                  function deScale(
                      uint256 a
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      return a.div(SCALE_FACTOR);
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                  * @dev Performs division where if there is a modulo, the value is rounded up
                  */
                  function divCeil(uint256 a, uint256 b)
                      internal
                      pure
                      returns(uint256)
                  {
                      return a.mod(b) > 0 ? a.div(b).add(1) : a.div(b);
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
                  /*
                   * Gets the rounded up log10 of passed value
                   *
                   * @param  _value         Value to calculate ceil(log()) on
                   * @return uint256        Output value
                   */
                  function ceilLog10(
                      uint256 _value
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Make sure passed value is greater than 0
                      require (
                          _value > 0,
                          "CommonMath.ceilLog10: Value must be greater than zero."
                      );
              
                      // Since log10(1) = 0, if _value = 1 return 0
                      if (_value == 1) return 0;
              
                      // Calcualte ceil(log10())
                      uint256 x = _value - 1;
              
                      uint256 result = 0;
              
                      if (x >= 10 ** 64) {
                          x /= 10 ** 64;
                          result += 64;
                      }
                      if (x >= 10 ** 32) {
                          x /= 10 ** 32;
                          result += 32;
                      }
                      if (x >= 10 ** 16) {
                          x /= 10 ** 16;
                          result += 16;
                      }
                      if (x >= 10 ** 8) {
                          x /= 10 ** 8;
                          result += 8;
                      }
                      if (x >= 10 ** 4) {
                          x /= 10 ** 4;
                          result += 4;
                      }
                      if (x >= 100) {
                          x /= 100;
                          result += 2;
                      }
                      if (x >= 10) {
                          result += 1;
                      }
              
                      return result + 1;
                  }
              }
              
              // File: contracts/core/lib/RebalancingLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title RebalancingLibrary
               * @author Set Protocol
               *
               * The RebalancingLibrary contains functions for facilitating the rebalancing process for
               * Rebalancing Set Tokens. Removes the old calculation functions
               *
               */
              library RebalancingLibrary {
              
                  /* ============ Enums ============ */
              
                  enum State { Default, Proposal, Rebalance, Drawdown }
              
                  /* ============ Structs ============ */
              
                  struct AuctionPriceParameters {
                      uint256 auctionStartTime;
                      uint256 auctionTimeToPivot;
                      uint256 auctionStartPrice;
                      uint256 auctionPivotPrice;
                  }
              
                  struct BiddingParameters {
                      uint256 minimumBid;
                      uint256 remainingCurrentSets;
                      uint256[] combinedCurrentUnits;
                      uint256[] combinedNextSetUnits;
                      address[] combinedTokenArray;
                  }
              }
              
              // File: contracts/core/interfaces/ICore.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ICore
               * @author Set Protocol
               *
               * The ICore Contract defines all the functions exposed in the Core through its
               * various extensions and is a light weight way to interact with the contract.
               */
              interface ICore {
                  /**
                   * Return transferProxy address.
                   *
                   * @return address       transferProxy address
                   */
                  function transferProxy()
                      external
                      view
                      returns (address);
              
                  /**
                   * Return vault address.
                   *
                   * @return address       vault address
                   */
                  function vault()
                      external
                      view
                      returns (address);
              
                  /**
                   * Return address belonging to given exchangeId.
                   *
                   * @param  _exchangeId       ExchangeId number
                   * @return address           Address belonging to given exchangeId
                   */
                  function exchangeIds(
                      uint8 _exchangeId
                  )
                      external
                      view
                      returns (address);
              
                  /*
                   * Returns if valid set
                   *
                   * @return  bool      Returns true if Set created through Core and isn't disabled
                   */
                  function validSets(address)
                      external
                      view
                      returns (bool);
              
                  /*
                   * Returns if valid module
                   *
                   * @return  bool      Returns true if valid module
                   */
                  function validModules(address)
                      external
                      view
                      returns (bool);
              
                  /**
                   * Return boolean indicating if address is a valid Rebalancing Price Library.
                   *
                   * @param  _priceLibrary    Price library address
                   * @return bool             Boolean indicating if valid Price Library
                   */
                  function validPriceLibraries(
                      address _priceLibrary
                  )
                      external
                      view
                      returns (bool);
              
                  /**
                   * Exchanges components for Set Tokens
                   *
                   * @param  _set          Address of set to issue
                   * @param  _quantity     Quantity of set to issue
                   */
                  function issue(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Issues a specified Set for a specified quantity to the recipient
                   * using the caller's components from the wallet and vault.
                   *
                   * @param  _recipient    Address to issue to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Converts user's components into Set Tokens held directly in Vault instead of user's account
                   *
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function issueInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Function to convert Set Tokens into underlying components
                   *
                   * @param _set          The address of the Set token
                   * @param _quantity     The number of tokens to redeem. Should be multiple of natural unit.
                   */
                  function redeem(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Redeem Set token and return components to specified recipient. The components
                   * are left in the vault
                   *
                   * @param _recipient    Recipient of Set being issued
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function redeemTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Function to convert Set Tokens held in vault into underlying components
                   *
                   * @param _set          The address of the Set token
                   * @param _quantity     The number of tokens to redeem. Should be multiple of natural unit.
                   */
                  function redeemInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Composite method to redeem and withdraw with a single transaction
                   *
                   * Normally, you should expect to be able to withdraw all of the tokens.
                   * However, some have central abilities to freeze transfers (e.g. EOS). _toExclude
                   * allows you to optionally specify which component tokens to exclude when
                   * redeeming. They will remain in the vault under the users' addresses.
                   *
                   * @param _set          Address of the Set
                   * @param _to           Address to withdraw or attribute tokens to
                   * @param _quantity     Number of tokens to redeem
                   * @param _toExclude    Mask of indexes of tokens to exclude from withdrawing
                   */
                  function redeemAndWithdrawTo(
                      address _set,
                      address _to,
                      uint256 _quantity,
                      uint256 _toExclude
                  )
                      external;
              
                  /**
                   * Deposit multiple tokens to the vault. Quantities should be in the
                   * order of the addresses of the tokens being deposited.
                   *
                   * @param  _tokens           Array of the addresses of the ERC20 tokens
                   * @param  _quantities       Array of the number of tokens to deposit
                   */
                  function batchDeposit(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Withdraw multiple tokens from the vault. Quantities should be in the
                   * order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _tokens            Array of the addresses of the ERC20 tokens
                   * @param  _quantities        Array of the number of tokens to withdraw
                   */
                  function batchWithdraw(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Deposit any quantity of tokens into the vault.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _quantity        The number of tokens to deposit
                   */
                  function deposit(
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Withdraw a quantity of tokens from the vault.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _quantity        The number of tokens to withdraw
                   */
                  function withdraw(
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Transfer tokens associated with the sender's account in vault to another user's
                   * account in vault.
                   *
                   * @param  _token           Address of token being transferred
                   * @param  _to              Address of user receiving tokens
                   * @param  _quantity        Amount of tokens being transferred
                   */
                  function internalTransfer(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _factory              The address of the Factory to create from
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address _factory,
                      address[] calldata _components,
                      uint256[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              
                  /**
                   * Exposes internal function that deposits a quantity of tokens to the vault and attributes
                   * the tokens respectively, to system modules.
                   *
                   * @param  _from            Address to transfer tokens from
                   * @param  _to              Address to credit for deposit
                   * @param  _token           Address of token being deposited
                   * @param  _quantity        Amount of tokens to deposit
                   */
                  function depositModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Exposes internal function that withdraws a quantity of tokens from the vault and
                   * deattributes the tokens respectively, to system modules.
                   *
                   * @param  _from            Address to decredit for withdraw
                   * @param  _to              Address to transfer tokens to
                   * @param  _token           Address of token being withdrawn
                   * @param  _quantity        Amount of tokens to withdraw
                   */
                  function withdrawModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Exposes internal function that deposits multiple tokens to the vault, to system
                   * modules. Quantities should be in the order of the addresses of the tokens being
                   * deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _tokens            Array of the addresses of the tokens being deposited
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDepositModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Exposes internal function that withdraws multiple tokens from the vault, to system
                   * modules. Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _tokens            Array of the addresses of the tokens being withdrawn
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdrawModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose internal function that exchanges components for Set tokens,
                   * accepting any owner, to system modules
                   *
                   * @param  _owner        Address to use tokens from
                   * @param  _recipient    Address to issue Set to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueModule(
                      address _owner,
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Expose internal function that exchanges Set tokens for components,
                   * accepting any owner, to system modules
                   *
                   * @param  _burnAddress         Address to burn token from
                   * @param  _incrementAddress    Address to increment component tokens to
                   * @param  _set                 Address of the Set to redeem
                   * @param  _quantity            Number of tokens to redeem
                   */
                  function redeemModule(
                      address _burnAddress,
                      address _incrementAddress,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Expose vault function that increments user's balance in the vault.
                   * Available to system modules
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose vault function that decrement user's balance in the vault
                   * Only available to system modules.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose vault function that transfer vault balances between users
                   * Only available to system modules.
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalanceModule(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Transfers token from one address to another using the transfer proxy.
                   * Only available to system modules.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _quantity       The number of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function transferModule(
                      address _token,
                      uint256 _quantity,
                      address _from,
                      address _to
                  )
                      external;
              
                  /**
                   * Expose transfer proxy function to transfer tokens from one address to another
                   * Only available to system modules.
                   *
                   * @param  _tokens         The addresses of the ERC20 token
                   * @param  _quantities     The numbers of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function batchTransferModule(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities,
                      address _from,
                      address _to
                  )
                      external;
              }
              
              // File: contracts/core/interfaces/IFeeCalculator.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IFeeCalculator
               * @author Set Protocol
               *
               */
              interface IFeeCalculator {
              
                  /* ============ External Functions ============ */
              
                  function initialize(
                      bytes calldata _feeCalculatorData
                  )
                      external;
              
                  function getFee()
                      external
                      view
                      returns(uint256);
              
                  function updateAndGetFee()
                      external
                      returns(uint256);
              
                  function adjustFee(
                      bytes calldata _newFeeData
                  )
                      external;
              }
              
              // File: contracts/core/interfaces/ISetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title ISetToken
               * @author Set Protocol
               *
               * The ISetToken interface provides a light-weight, structured way to interact with the
               * SetToken contract from another contract.
               */
              interface ISetToken {
              
                  /* ============ External Functions ============ */
              
                  /*
                   * Get natural unit of Set
                   *
                   * @return  uint256       Natural unit of Set
                   */
                  function naturalUnit()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get addresses of all components in the Set
                   *
                   * @return  componentAddresses       Array of component tokens
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get units of all tokens in Set
                   *
                   * @return  units       Array of component units
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Checks to make sure token is component of Set
                   *
                   * @param  _tokenAddress     Address of token being checked
                   * @return  bool             True if token is component of Set
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      external
                      view
                      returns (bool);
              
                  /*
                   * Mint set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Burn set token for given address
                   * Can only be called by authorized contracts
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                  * Transfer token for a specified address
                  *
                  * @param to The address to transfer to.
                  * @param value The amount to be transferred.
                  */
                  function transfer(
                      address to,
                      uint256 value
                  )
                      external;
              }
              
              // File: contracts/core/interfaces/IRebalancingSetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              pragma experimental "ABIEncoderV2";
              
              
              /**
               * @title IRebalancingSetToken
               * @author Set Protocol
               *
               * The IRebalancingSetToken interface provides a light-weight, structured way to interact with the
               * RebalancingSetToken contract from another contract.
               */
              
              interface IRebalancingSetToken {
              
                  /*
                   * Get the auction library contract used for the current rebalance
                   *
                   * @return address    Address of auction library used in the upcoming auction
                   */
                  function auctionLibrary()
                      external
                      view
                      returns (address);
              
                  /*
                   * Get totalSupply of Rebalancing Set
                   *
                   * @return  totalSupply
                   */
                  function totalSupply()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get proposalTimeStamp of Rebalancing Set
                   *
                   * @return  proposalTimeStamp
                   */
                  function proposalStartTime()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get lastRebalanceTimestamp of Rebalancing Set
                   *
                   * @return  lastRebalanceTimestamp
                   */
                  function lastRebalanceTimestamp()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get rebalanceInterval of Rebalancing Set
                   *
                   * @return  rebalanceInterval
                   */
                  function rebalanceInterval()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get rebalanceState of Rebalancing Set
                   *
                   * @return RebalancingLibrary.State    Current rebalance state of the RebalancingSetToken
                   */
                  function rebalanceState()
                      external
                      view
                      returns (RebalancingLibrary.State);
              
                  /*
                   * Get the starting amount of current SetToken for the current auction
                   *
                   * @return  rebalanceState
                   */
                  function startingCurrentSetAmount()
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Gets the balance of the specified address.
                   *
                   * @param owner      The address to query the balance of.
                   * @return           A uint256 representing the amount owned by the passed address.
                   */
                  function balanceOf(
                      address owner
                  )
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Function used to set the terms of the next rebalance and start the proposal period
                   *
                   * @param _nextSet                      The Set to rebalance into
                   * @param _auctionLibrary               The library used to calculate the Dutch Auction price
                   * @param _auctionTimeToPivot           The amount of time for the auction to go ffrom start to pivot price
                   * @param _auctionStartPrice            The price to start the auction at
                   * @param _auctionPivotPrice            The price at which the price curve switches from linear to exponential
                   */
                  function propose(
                      address _nextSet,
                      address _auctionLibrary,
                      uint256 _auctionTimeToPivot,
                      uint256 _auctionStartPrice,
                      uint256 _auctionPivotPrice
                  )
                      external;
              
                  /*
                   * Get natural unit of Set
                   *
                   * @return  uint256       Natural unit of Set
                   */
                  function naturalUnit()
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Returns the address of the current base SetToken with the current allocation
                   *
                   * @return           A address representing the base SetToken
                   */
                  function currentSet()
                      external
                      view
                      returns (address);
              
                  /**
                   * Returns the address of the next base SetToken with the post auction allocation
                   *
                   * @return  address    Address representing the base SetToken
                   */
                  function nextSet()
                      external
                      view
                      returns (address);
              
                  /*
                   * Get the unit shares of the rebalancing Set
                   *
                   * @return  unitShares       Unit Shares of the base Set
                   */
                  function unitShares()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Burn set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Place bid during rebalance auction. Can only be called by Core.
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   * @return combinedTokenArray       Array of token addresses invovled in rebalancing
                   * @return inflowUnitArray          Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray         Array of amount of tokens taken out of system in bid
                   */
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      returns (address[] memory, uint256[] memory, uint256[] memory);
              
                  /*
                   * Get combinedTokenArray of Rebalancing Set
                   *
                   * @return  combinedTokenArray
                   */
                  function getCombinedTokenArrayLength()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get combinedTokenArray of Rebalancing Set
                   *
                   * @return  combinedTokenArray
                   */
                  function getCombinedTokenArray()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get failedAuctionWithdrawComponents of Rebalancing Set
                   *
                   * @return  failedAuctionWithdrawComponents
                   */
                  function getFailedAuctionWithdrawComponents()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get auctionPriceParameters for current auction
                   *
                   * @return uint256[4]    AuctionPriceParameters for current rebalance auction
                   */
                  function getAuctionPriceParameters()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Get biddingParameters for current auction
                   *
                   * @return uint256[2]    BiddingParameters for current rebalance auction
                   */
                  function getBiddingParameters()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Get token inflows and outflows required for bid. Also the amount of Rebalancing
                   * Sets that would be generated.
                   *
                   * @param _quantity               The amount of currentSet to be rebalanced
                   * @return inflowUnitArray        Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray       Array of amount of tokens taken out of system in bid
                   */
                  function getBidPrice(
                      uint256 _quantity
                  )
                      external
                      view
                      returns (uint256[] memory, uint256[] memory);
              
              }
              
              // File: contracts/core/lib/Rebalance.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              /**
               * @title Rebalance
               * @author Set Protocol
               *
               * Types and functions for Rebalance-related data.
               */
              library Rebalance {
              
                  struct TokenFlow {
                      address[] addresses;
                      uint256[] inflow;
                      uint256[] outflow;
                  }
              
                  function composeTokenFlow(
                      address[] memory _addresses,
                      uint256[] memory _inflow,
                      uint256[] memory _outflow
                  )
                      internal
                      pure
                      returns(TokenFlow memory)
                  {
                      return TokenFlow({addresses: _addresses, inflow: _inflow, outflow: _outflow });
                  }
              
                  function decomposeTokenFlow(TokenFlow memory _tokenFlow)
                      internal
                      pure
                      returns (address[] memory, uint256[] memory, uint256[] memory)
                  {
                      return (_tokenFlow.addresses, _tokenFlow.inflow, _tokenFlow.outflow);
                  }
              
                  function decomposeTokenFlowToBidPrice(TokenFlow memory _tokenFlow)
                      internal
                      pure
                      returns (uint256[] memory, uint256[] memory)
                  {
                      return (_tokenFlow.inflow, _tokenFlow.outflow);
                  }
              
                  /**
                   * Get token flows array of addresses, inflows and outflows
                   *
                   * @param    _rebalancingSetToken   The rebalancing Set Token instance
                   * @param    _quantity              The amount of currentSet to be rebalanced
                   * @return   combinedTokenArray     Array of token addresses
                   * @return   inflowArray            Array of amount of tokens inserted into system in bid
                   * @return   outflowArray           Array of amount of tokens returned from system in bid
                   */
                  function getTokenFlows(
                      IRebalancingSetToken _rebalancingSetToken,
                      uint256 _quantity
                  )
                      internal
                      view
                      returns (address[] memory, uint256[] memory, uint256[] memory)
                  {
                      // Get token addresses
                      address[] memory combinedTokenArray = _rebalancingSetToken.getCombinedTokenArray();
              
                      // Get inflow and outflow arrays for the given bid quantity
                      (
                          uint256[] memory inflowArray,
                          uint256[] memory outflowArray
                      ) = _rebalancingSetToken.getBidPrice(_quantity);
              
                      return (combinedTokenArray, inflowArray, outflowArray);
                  }
              }
              
              // File: contracts/core/interfaces/ILiquidator.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title ILiquidator
               * @author Set Protocol
               *
               */
              interface ILiquidator {
              
                  /* ============ External Functions ============ */
              
                  function startRebalance(
                      ISetToken _currentSet,
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity,
                      bytes calldata _liquidatorData
                  )
                      external;
              
                  function getBidPrice(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      view
                      returns (Rebalance.TokenFlow memory);
              
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      returns (Rebalance.TokenFlow memory);
              
              
                  function settleRebalance()
                      external;
              
                  function endFailedRebalance() external;
              
                  // ----------------------------------------------------------------------
                  // Auction Price
                  // ----------------------------------------------------------------------
              
                  function auctionPriceParameters(address _set)
                      external
                      view
                      returns (RebalancingLibrary.AuctionPriceParameters memory);
              
                  // ----------------------------------------------------------------------
                  // Auction
                  // ----------------------------------------------------------------------
              
                  function hasRebalanceFailed(address _set) external view returns (bool);
                  function minimumBid(address _set) external view returns (uint256);
                  function startingCurrentSets(address _set) external view returns (uint256);
                  function remainingCurrentSets(address _set) external view returns (uint256);
                  function getCombinedCurrentSetUnits(address _set) external view returns (uint256[] memory);
                  function getCombinedNextSetUnits(address _set) external view returns (uint256[] memory);
                  function getCombinedTokenArray(address _set) external view returns (address[] memory);
              }
              
              // File: contracts/core/interfaces/ISetFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ISetFactory
               * @author Set Protocol
               *
               * The ISetFactory interface provides operability for authorized contracts
               * to interact with SetTokenFactory
               */
              interface ISetFactory {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Return core address
                   *
                   * @return address        core address
                   */
                  function core()
                      external
                      returns (address);
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address[] calldata _components,
                      uint[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              }
              
              // File: contracts/core/interfaces/IWhiteList.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IWhiteList
               * @author Set Protocol
               *
               * The IWhiteList interface exposes the whitelist mapping to check components
               */
              interface IWhiteList {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Validates address against white list
                   *
                   * @param  _address       Address to check
                   * @return bool           Whether passed in address is whitelisted
                   */
                  function whiteList(
                      address _address
                  )
                      external
                      view
                      returns (bool);
              
                  /**
                   * Verifies an array of addresses against the whitelist
                   *
                   * @param  _addresses    Array of addresses to verify
                   * @return bool          Whether all addresses in the list are whitelsited
                   */
                  function areValidAddresses(
                      address[] calldata _addresses
                  )
                      external
                      view
                      returns (bool);
              }
              
              // File: contracts/core/interfaces/IRebalancingSetFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title IRebalancingSetFactory
               * @author Set Protocol
               *
               * The IRebalancingSetFactory interface provides operability for authorized contracts
               * to interact with RebalancingSetTokenFactory
               */
              contract IRebalancingSetFactory is
                  ISetFactory
              {
                  /**
                   * Getter for minimumRebalanceInterval of RebalancingSetTokenFactory, used
                   * to enforce rebalanceInterval when creating a RebalancingSetToken
                   *
                   * @return uint256    Minimum amount of time between rebalances in seconds
                   */
                  function minimumRebalanceInterval()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for minimumProposalPeriod of RebalancingSetTokenFactory, used
                   * to enforce proposalPeriod when creating a RebalancingSetToken
                   *
                   * @return uint256    Minimum amount of time users can review proposals in seconds
                   */
                  function minimumProposalPeriod()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for minimumTimeToPivot of RebalancingSetTokenFactory, used
                   * to enforce auctionTimeToPivot when proposing a rebalance
                   *
                   * @return uint256    Minimum amount of time before auction pivot reached
                   */
                  function minimumTimeToPivot()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for maximumTimeToPivot of RebalancingSetTokenFactory, used
                   * to enforce auctionTimeToPivot when proposing a rebalance
                   *
                   * @return uint256    Maximum amount of time before auction pivot reached
                   */
                  function maximumTimeToPivot()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for minimumNaturalUnit of RebalancingSetTokenFactory
                   *
                   * @return uint256    Minimum natural unit
                   */
                  function minimumNaturalUnit()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for maximumNaturalUnit of RebalancingSetTokenFactory
                   *
                   * @return uint256    Maximum Minimum natural unit
                   */
                  function maximumNaturalUnit()
                      external
                      returns (uint256);
              
                  /**
                   * Getter for rebalanceAuctionModule address on RebalancingSetTokenFactory
                   *
                   * @return address      Address of rebalanceAuctionModule
                   */
                  function rebalanceAuctionModule()
                      external
                      returns (address);
              }
              
              // File: contracts/core/interfaces/IVault.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IVault
               * @author Set Protocol
               *
               * The IVault interface provides a light-weight, structured way to interact with the Vault
               * contract from another contract.
               */
              interface IVault {
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer token to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function withdrawTo(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Increment quantity owned of a token for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to attribute to owner
                   */
                  function incrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Decrement quantity owned of a token for a given address. Can only
                   * be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to deattribute to owner
                   */
                  function decrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _token          Address of token being transferred
                   * @param  _from           Address token being transferred from
                   * @param  _to             Address token being transferred to
                   * @param  _quantity       Amount of tokens being transferred
                   */
              
                  function transferBalance(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchWithdrawTo(
                      address[] calldata _tokens,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Increment quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Decrements quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                 /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalance(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Get balance of particular contract for owner.
                   *
                   * @param  _token    The address of the ERC20 token
                   * @param  _owner    The address of the token owner
                   */
                  function getOwnerBalance(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256);
              }
              
              // File: contracts/lib/ScaleValidations.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library ScaleValidations {
                  using SafeMath for uint256;
              
                  uint256 private constant ONE_HUNDRED_PERCENT = 1e18;
                  uint256 private constant ONE_BASIS_POINT = 1e14;
              
                  function validateLessThanEqualOneHundredPercent(uint256 _value) internal view {
                      require(_value <= ONE_HUNDRED_PERCENT, "Must be <= 100%");
                  }
              
                  function validateMultipleOfBasisPoint(uint256 _value) internal view {
                      require(
                          _value.mod(ONE_BASIS_POINT) == 0,
                          "Must be multiple of 0.01%"
                      );
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v2/RebalancingSetState.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              
              
              /**
               * @title RebalancingSetState
               * @author Set Protocol
               *
               */
              contract RebalancingSetState {
              
                  /* ============ State Variables ============ */
              
                  // ----------------------------------------------------------------------
                  // System Related
                  // ----------------------------------------------------------------------
              
                  // Set Protocol's Core Contract
                  ICore public core;
              
                  // The Factory that created this Set
                  IRebalancingSetFactory public factory;
              
                  // Set Protocol's Vault contract
                  IVault public vault;
              
                  // The token whitelist that components are checked against during proposals
                  IWhiteList public componentWhiteList;
              
                  // WhiteList of liquidator contracts
                  IWhiteList public liquidatorWhiteList;
              
                  // Contract holding the state and logic required for rebalance liquidation
                  // The Liquidator interacts closely with the Set during rebalances.
                  ILiquidator public liquidator;
              
                  // Contract responsible for calculation of rebalance fees
                  IFeeCalculator public rebalanceFeeCalculator;
              
                  // The account that is allowed to make proposals
                  address public manager;
              
                  // The account that receives any fees
                  address public feeRecipient;
              
                  // ----------------------------------------------------------------------
                  // Configuration
                  // ----------------------------------------------------------------------
              
                  // Time in seconds that must elapsed from last rebalance to propose
                  uint256 public rebalanceInterval;
              
                  // Time in seconds after rebalanceStartTime before the Set believes the auction has failed
                  uint256 public rebalanceFailPeriod;
              
                  // Fee levied to feeRecipient every mint operation, paid during minting
                  // Represents a decimal value scaled by 1e18 (e.g. 100% = 1e18 and 1% = 1e16)
                  uint256 public entryFee;
              
                  // ----------------------------------------------------------------------
                  // Current State
                  // ----------------------------------------------------------------------
              
                  // The Set currently collateralizing the Rebalancing Set
                  ISetToken public currentSet;
              
                  // The number of currentSet per naturalUnit of the Rebalancing Set
                  uint256 public unitShares;
              
                  // The minimum issuable value of a Set
                  uint256 public naturalUnit;
              
                  // The current state of the Set (e.g. Default, Proposal, Rebalance, Drawdown)
                  // Proposal is unused
                  RebalancingLibrary.State public rebalanceState;
              
                  // The number of rebalances in the Set's history; starts at index 0
                  uint256 public rebalanceIndex;
              
                  // The timestamp of the last completed rebalance
                  uint256 public lastRebalanceTimestamp;
              
                  // ----------------------------------------------------------------------
                  // Live Rebalance State
                  // ----------------------------------------------------------------------
              
                  // The proposal's SetToken to rebalance into
                  ISetToken public nextSet;
              
                  // The timestamp of the last rebalance was initiated at
                  uint256 public rebalanceStartTime;
              
                  // Whether a successful bid has been made during the rebalance.
                  // In the case that the rebalance has failed, hasBidded is used
                  // to determine whether the Set should be put into Drawdown or Default state.
                  bool public hasBidded;
              
                  // In the event a Set is put into the Drawdown state, these components
                  // that can be withdrawn by users
                  address[] internal failedRebalanceComponents;
              
                  /* ============ Modifier ============ */
              
                  modifier onlyManager() {
                      validateManager();
                      _;
                  }
              
                  /* ============ Events ============ */
              
                  event NewManagerAdded(
                      address newManager,
                      address oldManager
                  );
              
                  event NewLiquidatorAdded(
                      address newLiquidator,
                      address oldLiquidator
                  );
              
                  event NewEntryFee(
                      uint256 newEntryFee,
                      uint256 oldEntryFee
                  );
              
                  event NewFeeRecipient(
                      address newFeeRecipient,
                      address oldFeeRecipient
                  );
              
                  event EntryFeePaid(
                      address indexed feeRecipient,
                      uint256 feeQuantity
                  );
              
                  event RebalanceStarted(
                      address oldSet,
                      address newSet,
                      uint256 rebalanceIndex,
                      uint256 currentSetQuantity
                  );
              
                  event RebalanceSettled(
                      address indexed feeRecipient,
                      uint256 feeQuantity,
                      uint256 feePercentage,
                      uint256 rebalanceIndex,
                      uint256 issueQuantity,
                      uint256 unitShares
                  );
              
                  /* ============ Setter Functions ============ */
              
                  /*
                   * Set new manager address.
                   */
                  function setManager(
                      address _newManager
                  )
                      external
                      onlyManager
                  {
                      emit NewManagerAdded(_newManager, manager);
                      manager = _newManager;
                  }
              
                  function setEntryFee(
                      uint256 _newEntryFee
                  )
                      external
                      onlyManager
                  {
                      ScaleValidations.validateLessThanEqualOneHundredPercent(_newEntryFee);
              
                      ScaleValidations.validateMultipleOfBasisPoint(_newEntryFee);
              
                      emit NewEntryFee(_newEntryFee, entryFee);
                      entryFee = _newEntryFee;
                  }
              
                  /*
                   * Set new liquidator address. Only whitelisted addresses are valid.
                   */
                  function setLiquidator(
                      ILiquidator _newLiquidator
                  )
                      external
                      onlyManager
                  {
                      require(
                          rebalanceState != RebalancingLibrary.State.Rebalance,
                          "Invalid state"
                      );
              
                      require(
                          liquidatorWhiteList.whiteList(address(_newLiquidator)),
                          "Not whitelisted"
                      );
              
                      emit NewLiquidatorAdded(address(_newLiquidator), address(liquidator));
                      liquidator = _newLiquidator;
                  }
              
                  function setFeeRecipient(
                      address _newFeeRecipient
                  )
                      external
                      onlyManager
                  {
                      emit NewFeeRecipient(_newFeeRecipient, feeRecipient);
                      feeRecipient = _newFeeRecipient;
                  }
              
                  /* ============ Getter Functions ============ */
              
                  /*
                   * Retrieves the current expected fee from the fee calculator
                   * Value is returned as a scale decimal figure.
                   */
                  function rebalanceFee()
                      external
                      view
                      returns (uint256)
                  {
                      return rebalanceFeeCalculator.getFee();
                  }
              
                  /*
                   * Function for compatability with ISetToken interface. Returns currentSet.
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory)
                  {
                      address[] memory components = new address[](1);
                      components[0] = address(currentSet);
                      return components;
                  }
              
                  /*
                   * Function for compatability with ISetToken interface. Returns unitShares.
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory)
                  {
                      uint256[] memory units = new uint256[](1);
                      units[0] = unitShares;
                      return units;
                  }
              
                  /*
                   * Returns whether the address is the current set of the RebalancingSetToken.
                   * Conforms to the ISetToken Interface.
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      external
                      view
                      returns (bool)
                  {
                      return _tokenAddress == address(currentSet);
                  }
              
                  /* ============ Validations ============ */
                  function validateManager() internal view {
                      require(
                          msg.sender == manager,
                          "Not manager"
                      );
                  }
              
                  function validateCallerIsCore() internal view {
                      require(
                          msg.sender == address(core),
                          "Not Core"
                      );
                  }
              
                  function validateCallerIsModule() internal view {
                      require(
                          core.validModules(msg.sender),
                          "Not approved module"
                      );
                  }
              
                  function validateRebalanceStateIs(RebalancingLibrary.State _requiredState) internal view {
                      require(
                          rebalanceState == _requiredState,
                          "Invalid state"
                      );
                  }
              
                  function validateRebalanceStateIsNot(RebalancingLibrary.State _requiredState) internal view {
                      require(
                          rebalanceState != _requiredState,
                          "Invalid state"
                      );
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v3/IncentiveFee.sol
              
              /*
                  Copyright 2020 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              /**
               * @title IncentiveFee
               * @author Set Protocol
               */
              contract IncentiveFee is
                  ERC20,
                  RebalancingSetState
              {
                  using SafeMath for uint256;
                  using CommonMath for uint256;
              
                  /* ============ Events ============ */
              
                  event IncentiveFeePaid(
                      address indexed feeRecipient,
                      uint256 feeQuantity,
                      uint256 feePercentage,
                      uint256 newUnitShares
                  );
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Calculates the fee and mints the rebalancing SetToken quantity to the recipient.
                   * The minting is done without an increase to the total collateral controlled by the
                   * rebalancing SetToken. In effect, the existing holders are paying the fee via inflation.
                   *
                   * @return feePercentage
                   * @return feeQuantity
                   */
                  function handleFees()
                      internal
                      returns (uint256, uint256)
                  {
                      // Represents a decimal value scaled by 1e18 (e.g. 100% = 1e18 and 1% = 1e16)
                      uint256 feePercent = rebalanceFeeCalculator.updateAndGetFee();
                      uint256 feeQuantity = calculateIncentiveFeeInflation(feePercent);
              
                      if (feeQuantity > 0) {
                          ERC20._mint(feeRecipient, feeQuantity);
                      }
              
                      return (feePercent, feeQuantity);
                  }
              
                  /**
                   * Returns the new incentive fee. The calculation for the fee involves implying
                   * mint quantity so that the feeRecipient owns the fee percentage of the entire
                   * supply of the Set.
                   *
                   * The formula to solve for fee is:
                   * feeQuantity / feeQuantity + totalSupply = fee / scaleFactor
                   *
                   * The simplified formula utilized below is:
                   * feeQuantity = fee * totalSupply / (scaleFactor - fee)
                   *
                   * @param   _feePercentage          Fee levied to feeRecipient
                   * @return  uint256                 New RebalancingSet issue quantity
                   */
                  function calculateIncentiveFeeInflation(
                      uint256 _feePercentage
                  )
                      internal
                      view
                      returns(uint256)
                  {
                      // fee * totalSupply
                      uint256 a = _feePercentage.mul(totalSupply());
              
                      // ScaleFactor (10e18) - fee
                      uint256 b = CommonMath.scaleFactor().sub(_feePercentage);
              
                      return a.div(b);
                  }
              
                  /*
                   * The Rebalancing SetToken must be in Default state.
                   */
                  function validateFeeActualization() internal view {
                      validateRebalanceStateIs(RebalancingLibrary.State.Default);
                  }
              
                  /*
                   * After the minting of new inflation fees, the unit shares must be updated.
                   * The formula is as follows:
                   * newUnitShares = currentSetAmount * rebalanceSetNaturalUnit / rebalanceSetTotalSupply
                   */
                  function calculateNewUnitShares() internal view returns(uint256) {
                      uint256 currentSetAmount = vault.getOwnerBalance(
                          address(currentSet),
                          address(this)
                      );
              
                      return currentSetAmount.mul(naturalUnit).divCeil(totalSupply());
                  }
              }
              
              // File: openzeppelin-solidity/contracts/math/Math.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Math
               * @dev Assorted math operations
               */
              library Math {
                  /**
                   * @dev Returns the largest of two numbers.
                   */
                  function max(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a >= b ? a : b;
                  }
              
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a < b ? a : b;
                  }
              
                  /**
                   * @dev Calculates the average of two numbers. Since these are integers,
                   * averages of an even and odd number cannot be represented, and will be
                   * rounded down.
                   */
                  function average(uint256 a, uint256 b) internal pure returns (uint256) {
                      // (a + b) / 2 can overflow, so we distribute
                      return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
                  }
              }
              
              // File: contracts/core/lib/SetTokenLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              library SetTokenLibrary {
                  using SafeMath for uint256;
              
                  struct SetDetails {
                      uint256 naturalUnit;
                      address[] components;
                      uint256[] units;
                  }
              
                  /**
                   * Validates that passed in tokens are all components of the Set
                   *
                   * @param _set                      Address of the Set
                   * @param _tokens                   List of tokens to check
                   */
                  function validateTokensAreComponents(
                      address _set,
                      address[] calldata _tokens
                  )
                      external
                      view
                  {
                      for (uint256 i = 0; i < _tokens.length; i++) {
                          // Make sure all tokens are members of the Set
                          require(
                              ISetToken(_set).tokenIsComponent(_tokens[i]),
                              "SetTokenLibrary.validateTokensAreComponents: Component must be a member of Set"
                          );
              
                      }
                  }
              
                  /**
                   * Validates that passed in quantity is a multiple of the natural unit of the Set.
                   *
                   * @param _set                      Address of the Set
                   * @param _quantity                 Quantity to validate
                   */
                  function isMultipleOfSetNaturalUnit(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      view
                  {
                      require(
                          _quantity.mod(ISetToken(_set).naturalUnit()) == 0,
                          "SetTokenLibrary.isMultipleOfSetNaturalUnit: Quantity is not a multiple of nat unit"
                      );
                  }
              
                  /**
                   * Validates that passed in quantity is a multiple of the natural unit of the Set.
                   *
                   * @param _core                     Address of Core
                   * @param _set                      Address of the Set
                   */
                  function requireValidSet(
                      ICore _core,
                      address _set
                  )
                      internal
                      view
                  {
                      require(
                          _core.validSets(_set),
                          "SetTokenLibrary: Must be an approved SetToken address"
                      );
                  }
              
                  /**
                   * Retrieves the Set's natural unit, components, and units.
                   *
                   * @param _set                      Address of the Set
                   * @return SetDetails               Struct containing the natural unit, components, and units
                   */
                  function getSetDetails(
                      address _set
                  )
                      internal
                      view
                      returns (SetDetails memory)
                  {
                      // Declare interface variables
                      ISetToken setToken = ISetToken(_set);
              
                      // Fetch set token properties
                      uint256 naturalUnit = setToken.naturalUnit();
                      address[] memory components = setToken.getComponents();
                      uint256[] memory units = setToken.getUnits();
              
                      return SetDetails({
                          naturalUnit: naturalUnit,
                          components: components,
                          units: units
                      });
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v2/RebalancingSettlement.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              
              
              /**
               * @title RebalancingSettlement
               * @author Set Protocol
               *
               */
              contract RebalancingSettlement is
                  ERC20,
                  RebalancingSetState
              {
                  using SafeMath for uint256;
              
                  uint256 public constant SCALE_FACTOR = 10 ** 18;
              
                  /* ============ Internal Functions ============ */
              
                  /*
                   * Validates that the settle function can be called.
                   */
                  function validateRebalancingSettlement()
                      internal
                      view
                  {
                      validateRebalanceStateIs(RebalancingLibrary.State.Rebalance);
                  }
              
                  /*
                   * Issue nextSet to RebalancingSetToken; The issued Set is held in the Vault
                   *
                   * @param  _issueQuantity   Quantity of next Set to issue
                   */
                  function issueNextSet(
                      uint256 _issueQuantity
                  )
                      internal
                  {
                      core.issueInVault(
                          address(nextSet),
                          _issueQuantity
                      );
                  }
              
                  /*
                   * Updates state post-settlement.
                   *
                   * @param  _nextUnitShares   The new implied unit shares
                   */
                  function transitionToDefault(
                      uint256 _newUnitShares
                  )
                      internal
                  {
                      rebalanceState = RebalancingLibrary.State.Default;
                      lastRebalanceTimestamp = block.timestamp;
                      currentSet = nextSet;
                      unitShares = _newUnitShares;
                      rebalanceIndex = rebalanceIndex.add(1);
              
                      nextSet = ISetToken(address(0));
                      hasBidded = false;
                  }
              
                  /**
                   * Calculate the amount of Sets to issue by using the component amounts in the
                   * vault.
                   */
                  function calculateSetIssueQuantity(
                      ISetToken _setToken
                  )
                      internal
                      view
                      returns (uint256)
                  {
                      // Collect data necessary to compute issueAmounts
                      SetTokenLibrary.SetDetails memory setToken = SetTokenLibrary.getSetDetails(address(_setToken));
                      uint256 maxIssueAmount = calculateMaxIssueAmount(setToken);
              
                      // Issue amount of Sets that is closest multiple of nextNaturalUnit to the maxIssueAmount
                      uint256 issueAmount = maxIssueAmount.sub(maxIssueAmount.mod(setToken.naturalUnit));
              
                      return issueAmount;
                  }
              
                  /**
                   * Calculates the fee and mints the rebalancing SetToken quantity to the recipient.
                   * The minting is done without an increase to the total collateral controlled by the
                   * rebalancing SetToken. In effect, the existing holders are paying the fee via inflation.
                   *
                   * @return feePercentage
                   * @return feeQuantity
                   */
                  function handleFees()
                      internal
                      returns (uint256, uint256)
                  {
                      // Represents a decimal value scaled by 1e18 (e.g. 100% = 1e18 and 1% = 1e16)
                      uint256 feePercent = rebalanceFeeCalculator.getFee();
                      uint256 feeQuantity = calculateRebalanceFeeInflation(feePercent);
              
                      if (feeQuantity > 0) {
                          ERC20._mint(feeRecipient, feeQuantity);
                      }
              
                      return (feePercent, feeQuantity);
                  }
              
                  /**
                   * Returns the new rebalance fee. The calculation for the fee involves implying
                   * mint quantity so that the feeRecipient owns the fee percentage of the entire
                   * supply of the Set.
                   *
                   * The formula to solve for fee is:
                   * feeQuantity / feeQuantity + totalSupply = fee / scaleFactor
                   *
                   * The simplified formula utilized below is:
                   * feeQuantity = fee * totalSupply / (scaleFactor - fee)
                   *
                   * @param   _rebalanceFeePercent    Fee levied to feeRecipient every rebalance, paid during settlement
                   * @return  uint256                 New RebalancingSet issue quantity
                   */
                  function calculateRebalanceFeeInflation(
                      uint256 _rebalanceFeePercent
                  )
                      internal
                      view
                      returns(uint256)
                  {
                      // fee * totalSupply
                      uint256 a = _rebalanceFeePercent.mul(totalSupply());
              
                      // ScaleFactor (10e18) - fee
                      uint256 b = SCALE_FACTOR.sub(_rebalanceFeePercent);
              
                      return a.div(b);
                  }
              
                  /**
                   * Calculates the new unitShares, defined as issueQuantity / naturalUnitsOutstanding
                   *
                   * @param  _issueQuantity   Amount of nextSets to issue
                   *
                   * @return  uint256             New unitShares for the rebalancingSetToken
                   */
                  function calculateNextSetNewUnitShares(
                      uint256 _issueQuantity
                  )
                      internal
                      view
                      returns (uint256)
                  {
                      // Calculate the amount of naturalUnits worth of rebalancingSetToken outstanding.
                      uint256 naturalUnitsOutstanding = totalSupply().div(naturalUnit);
              
                      // Divide final issueAmount by naturalUnitsOutstanding to get newUnitShares
                      return _issueQuantity.div(naturalUnitsOutstanding);
                  }
              
                  /* ============ Private Functions ============ */
              
                  /**
                   * Get the maximum possible issue amount of nextSet based on number of components owned by rebalancing
                   * set token.
                   *
                   * @param  _setToken    Struct of Set Token details
                   */
                  function calculateMaxIssueAmount(
                      SetTokenLibrary.SetDetails memory _setToken
                  )
                      private
                      view
                      returns (uint256)
                  {
                      uint256 maxIssueAmount = CommonMath.maxUInt256();
              
                      for (uint256 i = 0; i < _setToken.components.length; i++) {
                          // Get amount of components in vault owned by rebalancingSetToken
                          uint256 componentAmount = vault.getOwnerBalance(
                              _setToken.components[i],
                              address(this)
                          );
              
                          // Calculate amount of Sets that can be issued from those components, if less than amount for other
                          // components then set that as maxIssueAmount. We divide before multiplying so that we don't get
                          // an amount that isn't a multiple of the naturalUnit
                          uint256 componentIssueAmount = componentAmount.div(_setToken.units[i]).mul(_setToken.naturalUnit);
                          if (componentIssueAmount < maxIssueAmount) {
                              maxIssueAmount = componentIssueAmount;
                          }
                      }
              
                      return maxIssueAmount;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
              
              pragma solidity ^0.5.2;
              
              
              /**
               * @title ERC20Detailed token
               * @dev The decimals are only for visualization purposes.
               * All the operations are done using the smallest and indivisible token unit,
               * just as on Ethereum all the operations are done in wei.
               */
              contract ERC20Detailed is IERC20 {
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
              
                  constructor (string memory name, string memory symbol, uint8 decimals) public {
                      _name = name;
                      _symbol = symbol;
                      _decimals = decimals;
                  }
              
                  /**
                   * @return the name of the token.
                   */
                  function name() public view returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @return the symbol of the token.
                   */
                  function symbol() public view returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @return the number of decimals of the token.
                   */
                  function decimals() public view returns (uint8) {
                      return _decimals;
                  }
              }
              
              // File: zos-lib/contracts/Initializable.sol
              
              pragma solidity >=0.4.24 <0.6.0;
              
              
              /**
               * @title Initializable
               *
               * @dev Helper contract to support initializer functions. To use it, replace
               * the constructor with a function that has the `initializer` modifier.
               * WARNING: Unlike constructors, initializer functions must be manually
               * invoked. This applies both to deploying an Initializable contract, as well
               * as extending an Initializable contract via inheritance.
               * WARNING: When used with inheritance, manual care must be taken to not invoke
               * a parent initializer twice, or ensure that all initializers are idempotent,
               * because this is not dealt with automatically as with constructors.
               */
              contract Initializable {
              
                /**
                 * @dev Indicates that the contract has been initialized.
                 */
                bool private initialized;
              
                /**
                 * @dev Indicates that the contract is in the process of being initialized.
                 */
                bool private initializing;
              
                /**
                 * @dev Modifier to use in the initializer function of a contract.
                 */
                modifier initializer() {
                  require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
              
                  bool isTopLevelCall = !initializing;
                  if (isTopLevelCall) {
                    initializing = true;
                    initialized = true;
                  }
              
                  _;
              
                  if (isTopLevelCall) {
                    initializing = false;
                  }
                }
              
                /// @dev Returns true if and only if the function is running in the constructor
                function isConstructor() private view returns (bool) {
                  // extcodesize checks the size of the code stored in an address, and
                  // address returns the current address. Since the code is still not
                  // deployed when running a constructor, any checks on its code size will
                  // yield zero, making it an effective way to detect if a contract is
                  // under construction or not.
                  uint256 cs;
                  assembly { cs := extcodesize(address) }
                  return cs == 0;
                }
              
                // Reserved storage space to allow for layout changes in the future.
                uint256[50] private ______gap;
              }
              
              // File: contracts/core/tokens/rebalancing-v2/BackwardCompatibility.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title BackwardCompatibility
               * @author Set Protocol
               *
               * This module allows full backwards compatability with RebalancingSetTokenV1. It implements
               * all the same getter functions to allow upstream applications to make minimized changes
               * to support the new version.
               *
               * The following interfaces are not included:
               * - propose(address, address, uint256, uint256, uint256): Implementation would have
               *.    been a revert.
               * - biddingParameters: RebalancingSetToken V1 biddingParameters reverts on call
               */
              contract BackwardCompatibility is
                  RebalancingSetState
              {
                  /* ============ Empty Variables ============ */
              
                  // Deprecated auctionLibrary. Returns 0x00 to prevent reverts
                  address public auctionLibrary;
              
                  // Deprecated proposal period. Returns 0 to prevent reverts
                  uint256 public proposalPeriod;
              
                  // Deprecated proposal start time. Returns 0 to prevent reverts
                  uint256 public proposalStartTime;
              
                  /* ============ Getters ============ */
              
                  function getAuctionPriceParameters() external view returns (uint256[] memory) {
                      RebalancingLibrary.AuctionPriceParameters memory params = liquidator.auctionPriceParameters(
                          address(this)
                      );
              
                      uint256[] memory auctionPriceParams = new uint256[](4);
                      auctionPriceParams[0] = params.auctionStartTime;
                      auctionPriceParams[1] = params.auctionTimeToPivot;
                      auctionPriceParams[2] = params.auctionStartPrice;
                      auctionPriceParams[3] = params.auctionPivotPrice;
              
                      return auctionPriceParams;
                  }
              
                  function getCombinedCurrentUnits() external view returns (uint256[] memory) {
                      return liquidator.getCombinedCurrentSetUnits(address(this));
                  }
              
                  function getCombinedNextSetUnits() external view returns (uint256[] memory) {
                      return liquidator.getCombinedNextSetUnits(address(this));
                  }
              
                  function getCombinedTokenArray() external view returns (address[] memory) {
                      return liquidator.getCombinedTokenArray(address(this));
                  }
              
                  function getCombinedTokenArrayLength() external view returns (uint256) {
                      return liquidator.getCombinedTokenArray(address(this)).length;
                  }
              
                  function startingCurrentSetAmount() external view returns (uint256) {
                      return liquidator.startingCurrentSets(address(this));
                  }
              
                  function auctionPriceParameters() external view
                      returns (RebalancingLibrary.AuctionPriceParameters memory)
                  {
                      return liquidator.auctionPriceParameters(address(this));
                  }
              
                  /*
                   * Since structs with arrays cannot be retrieved, we return
                   * minimumBid and remainingCurrentSets separately.
                   *
                   * @return  biddingParams       Array with minimumBid and remainingCurrentSets
                   */
                  function getBiddingParameters() public view returns (uint256[] memory) {
                      uint256[] memory biddingParams = new uint256[](2);
                      biddingParams[0] = liquidator.minimumBid(address(this));
                      biddingParams[1] = liquidator.remainingCurrentSets(address(this));
                      return biddingParams;
                  }
              
                  function biddingParameters()
                      external
                      view
                      returns (uint256, uint256)
                  {
                      uint256[] memory biddingParams = getBiddingParameters();
                      return (biddingParams[0], biddingParams[1]);
                  }
              
                  function getFailedAuctionWithdrawComponents() external view returns (address[] memory) {
                      return failedRebalanceComponents;
                  }
              }
              
              // File: contracts/lib/AddressArrayUtils.sol
              
              // Pulled in from Cryptofin Solidity package in order to control Solidity compiler version
              // https://github.com/cryptofinlabs/cryptofin-solidity/blob/master/contracts/array-utils/AddressArrayUtils.sol
              
              pragma solidity 0.5.7;
              
              
              library AddressArrayUtils {
              
                  /**
                   * Finds the index of the first occurrence of the given element.
                   * @param A The input array to search
                   * @param a The value to find
                   * @return Returns (index and isIn) for the first occurrence starting from index 0
                   */
                  function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length; i++) {
                          if (A[i] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                  * Returns true if the value is present in the list. Uses indexOf internally.
                  * @param A The input array to search
                  * @param a The value to find
                  * @return Returns isIn for the first occurrence starting from index 0
                  */
                  function contains(address[] memory A, address a) internal pure returns (bool) {
                      bool isIn;
                      (, isIn) = indexOf(A, a);
                      return isIn;
                  }
              
                  /**
                   * Returns the combination of the two arrays
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A extended by B
                   */
                  function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 aLength = A.length;
                      uint256 bLength = B.length;
                      address[] memory newAddresses = new address[](aLength + bLength);
                      for (uint256 i = 0; i < aLength; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = 0; j < bLength; j++) {
                          newAddresses[aLength + j] = B[j];
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the array with a appended to A.
                   * @param A The first array
                   * @param a The value to append
                   * @return Returns A appended by a
                   */
                  function append(address[] memory A, address a) internal pure returns (address[] memory) {
                      address[] memory newAddresses = new address[](A.length + 1);
                      for (uint256 i = 0; i < A.length; i++) {
                          newAddresses[i] = A[i];
                      }
                      newAddresses[A.length] = a;
                      return newAddresses;
                  }
              
                  /**
                   * Returns the intersection of two arrays. Arrays are treated as collections, so duplicates are kept.
                   * @param A The first array
                   * @param B The second array
                   * @return The intersection of the two arrays
                   */
                  function intersect(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 newLength = 0;
                      for (uint256 i = 0; i < length; i++) {
                          if (contains(B, A[i])) {
                              includeMap[i] = true;
                              newLength++;
                          }
                      }
                      address[] memory newAddresses = new address[](newLength);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the union of the two arrays. Order is not guaranteed.
                   * @param A The first array
                   * @param B The second array
                   * @return The union of the two arrays
                   */
                  function union(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      address[] memory leftDifference = difference(A, B);
                      address[] memory rightDifference = difference(B, A);
                      address[] memory intersection = intersect(A, B);
                      return extend(leftDifference, extend(intersection, rightDifference));
                  }
              
                  /**
                   * Computes the difference of two arrays. Assumes there are no duplicates.
                   * @param A The first array
                   * @param B The second array
                   * @return The difference of the two arrays
                   */
                  function difference(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 count = 0;
                      // First count the new length because can't push for in-memory arrays
                      for (uint256 i = 0; i < length; i++) {
                          address e = A[i];
                          if (!contains(B, e)) {
                              includeMap[i] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                  * Removes specified index from array
                  * Resulting ordering is not guaranteed
                  * @return Returns the new array and the removed entry
                  */
                  function pop(address[] memory A, uint256 index)
                      internal
                      pure
                      returns (address[] memory, address)
                  {
                      uint256 length = A.length;
                      address[] memory newAddresses = new address[](length - 1);
                      for (uint256 i = 0; i < index; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = index + 1; j < length; j++) {
                          newAddresses[j - 1] = A[j];
                      }
                      return (newAddresses, A[index]);
                  }
              
                  /**
                   * @return Returns the new array
                   */
                  function remove(address[] memory A, address a)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert();
                      } else {
                          (address[] memory _A,) = pop(A, index);
                          return _A;
                      }
                  }
              
                  /**
                   * Returns whether or not there's a duplicate. Runs in O(n^2).
                   * @param A Array to search
                   * @return Returns true if duplicate, false otherwise
                   */
                  function hasDuplicate(address[] memory A) internal pure returns (bool) {
                      if (A.length == 0) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length - 1; i++) {
                          for (uint256 j = i + 1; j < A.length; j++) {
                              if (A[i] == A[j]) {
                                  return true;
                              }
                          }
                      }
                      return false;
                  }
              
                  /**
                   * Returns whether the two arrays are equal.
                   * @param A The first array
                   * @param B The second array
                   * @return True is the arrays are equal, false if not.
                   */
                  function isEqual(address[] memory A, address[] memory B) internal pure returns (bool) {
                      if (A.length != B.length) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length; i++) {
                          if (A[i] != B[i]) {
                              return false;
                          }
                      }
                      return true;
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v2/RebalancingFailure.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              /**
               * @title RebalancingFailure
               * @author Set Protocol
               *
               */
              contract RebalancingFailure is
                  RebalancingSetState,
                  RebalancingSettlement
              {
                  using SafeMath for uint256;
                  using AddressArrayUtils for address[];
              
                  /* ============ Internal Functions ============ */
              
                  /*
                   * Validations for failRebalance:
                   *  - State is Rebalance
                   *  - Either liquidator recognizes failure OR fail period breached on RB Set
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   */
                  function validateFailRebalance()
                      internal
                      view
                  {
                      // Token must be in Rebalance State
                      validateRebalanceStateIs(RebalancingLibrary.State.Rebalance);
              
                      // Failure triggers must be met
                      require(
                          liquidatorBreached() || failPeriodBreached(),
                          "Triggers not breached"
                      );
                  }
              
                  /*
                   * Determine the new Rebalance State. If there has been a bid, then we put it to
                   * Drawdown, where the Set is effectively killed. If no bids, we reissue the currentSet.
                   */
                  function getNewRebalanceState()
                      internal
                      view
                      returns (RebalancingLibrary.State)
                  {
                      return hasBidded ? RebalancingLibrary.State.Drawdown : RebalancingLibrary.State.Default;
                  }
              
                  /*
                   * Update state based on new Rebalance State.
                   *
                   * @param  _newRebalanceState      The new State to transition to
                   */
                  function transitionToNewState(
                      RebalancingLibrary.State _newRebalanceState
                  )
                      internal
                  {
                      reissueSetIfRevertToDefault(_newRebalanceState);
              
                      setWithdrawComponentsIfDrawdown(_newRebalanceState);
              
                      rebalanceState = _newRebalanceState;
                      rebalanceIndex = rebalanceIndex.add(1);
                      lastRebalanceTimestamp = block.timestamp;
              
                      nextSet = ISetToken(address(0));
                      hasBidded = false;
                  }
              
                  /* ============ Private Functions ============ */
              
                  /*
                   * Returns whether the liquidator believes the rebalance has failed.
                   *
                   * @return        If liquidator thinks rebalance failed
                   */
                  function liquidatorBreached()
                      private
                      view
                      returns (bool)
                  {
                      return liquidator.hasRebalanceFailed(address(this));
                  }
              
                  /*
                   * Returns whether the the fail time has elapsed, which means that a period
                   * of time where the auction should have succeeded has not.
                   *
                   * @return        If fail period has passed on Rebalancing Set Token
                   */
                  function failPeriodBreached()
                      private
                      view
                      returns(bool)
                  {
                      uint256 rebalanceFailTime = rebalanceStartTime.add(rebalanceFailPeriod);
              
                      return block.timestamp >= rebalanceFailTime;
                  }
              
                  /*
                   * If the determination is Default State, reissue the Set.
                   */
                  function reissueSetIfRevertToDefault(
                      RebalancingLibrary.State _newRebalanceState
                  )
                      private
                  {
                      if (_newRebalanceState ==  RebalancingLibrary.State.Default) {
                          uint256 issueQuantity = calculateSetIssueQuantity(currentSet);
              
                          // If bid not placed, reissue current Set
                          core.issueInVault(
                              address(currentSet),
                              issueQuantity
                          );
                      }
                  }
              
                  /*
                   * If the determination is Drawdown State, set the drawdown components which is the union of
                   * the current and next Set components.
                   */
                  function setWithdrawComponentsIfDrawdown(
                      RebalancingLibrary.State _newRebalanceState
                  )
                      private
                  {
                      if (_newRebalanceState ==  RebalancingLibrary.State.Drawdown) {
                          address[] memory currentSetComponents = currentSet.getComponents();
                          address[] memory nextSetComponents = nextSet.getComponents();
              
                          failedRebalanceComponents = currentSetComponents.union(nextSetComponents);
                      }
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v2/Issuance.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              /**
               * @title Issuance
               * @author Set Protocol
               *
               * Default implementation of Rebalancing Set Token propose function
               */
              contract Issuance is
                  ERC20,
                  RebalancingSetState
              {
                  using SafeMath for uint256;
                  using CommonMath for uint256;
              
                  /* ============ Internal Functions ============ */
              
                  /*
                   * Validate call to mint new Rebalancing Set Token
                   *
                   *  - Make sure caller is Core
                   *  - Make sure state is not Rebalance or Drawdown
                   */
                  function validateMint()
                      internal
                      view
                  {
                      validateCallerIsCore();
              
                      validateRebalanceStateIs(RebalancingLibrary.State.Default);
                  }
              
                  /*
                   * Validate call to burn Rebalancing Set Token
                   *
                   *  - Make sure state is not Rebalance or Drawdown
                   *  - Make sure sender is module when in drawdown, core otherwise
                   */
                  function validateBurn()
                      internal
                      view
                  {
                      validateRebalanceStateIsNot(RebalancingLibrary.State.Rebalance);
              
                      if (rebalanceState == RebalancingLibrary.State.Drawdown) {
                          // In Drawdown Sets can only be burned as part of the withdrawal process
                          validateCallerIsModule();
                      } else {
                          // When in non-Rebalance or Drawdown state, check that function caller is Core
                          // so that Sets can be redeemed
                          validateCallerIsCore();
                      }
                  }
                  /*
                   * Calculates entry fees and mints the feeRecipient a portion of the issue quantity.
                   *
                   * @param  _quantity              The number of rebalancing SetTokens the issuer mints
                   * @return issueQuantityNetOfFees Quantity of rebalancing SetToken to mint issuer net of fees
                   */
                  function handleEntryFees(
                      uint256 _quantity
                  )
                      internal
                      returns(uint256)
                  {
                      // The entryFee is a scaled decimal figure by 10e18. We multiply the fee by the quantity
                      // Then descale by 10e18
                      uint256 fee = _quantity.mul(entryFee).deScale();
              
                      if (fee > 0) {
                          ERC20._mint(feeRecipient, fee);
              
                          emit EntryFeePaid(feeRecipient, fee);
                      }
              
                      // Return the issue quantity less fees
                      return _quantity.sub(fee);
                  }
              }
              
              // File: contracts/core/tokens/rebalancing-v2/RebalancingBid.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              /**
               * @title RebalancingBid
               * @author Set Protocol
               *
               * Implementation of Rebalancing Set Token V2 bidding-related functionality.
               */
              contract RebalancingBid is
                  RebalancingSetState
              {
                  using SafeMath for uint256;
              
                  /* ============ Internal Functions ============ */
              
                  /*
                   * Validates conditions to retrieve a Bid Price:
                   *  - State is Rebalance
                   *  - Quanity is greater than zero
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   */
                  function validateGetBidPrice(
                      uint256 _quantity
                  )
                      internal
                      view
                  {
                      validateRebalanceStateIs(RebalancingLibrary.State.Rebalance);
              
                      require(
                          _quantity > 0,
                          "Bid not > 0"
                      );
                  }
              
                  /*
                   * Validations for placeBid:
                   *  - Module is sender
                   *  - getBidPrice validations
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   */
                  function validatePlaceBid(
                      uint256 _quantity
                  )
                      internal
                      view
                  {
                      validateCallerIsModule();
              
                      validateGetBidPrice(_quantity);
                  }
              
                  /*
                   * If a successful bid has been made, flip the hasBidded boolean.
                   */
                  function updateHasBiddedIfNecessary()
                      internal
                  {
                      if (!hasBidded) {
                          hasBidded = true;
                      }
                  }
              
              }
              
              // File: contracts/core/tokens/rebalancing-v2/RebalancingStart.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              /**
               * @title RebalancingStart
               * @author Set Protocol
               *
               * Implementation of Rebalancing Set Token V2 start rebalance functionality
               */
              contract RebalancingStart is
                  ERC20,
                  RebalancingSetState
              {
                  using SafeMath for uint256;
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Validate that start rebalance can be called:
                   *  - Current state is Default
                   *  - rebalanceInterval has elapsed
                   *  - Proposed set is valid in Core
                   *  - Components in set are all valid
                   *  - NaturalUnits are multiples of each other
                   *
                   * @param _nextSet                    The Set to rebalance into
                   */
                  function validateStartRebalance(
                      ISetToken _nextSet
                  )
                      internal
                      view
                  {
                      validateRebalanceStateIs(RebalancingLibrary.State.Default);
              
                      // Enough time must have passed from last rebalance to start a new proposal
                      require(
                          block.timestamp >= lastRebalanceTimestamp.add(rebalanceInterval),
                          "Interval not elapsed"
                      );
              
                      // Must be a positive supply of the Set
                      require(
                          totalSupply() > 0,
                          "Invalid supply"
                      );
              
                      // New proposed Set must be a valid Set created by Core
                      require(
                          core.validSets(address(_nextSet)),
                          "Invalid Set"
                      );
              
                      // Check proposed components on whitelist. This is to ensure managers are unable to add contract addresses
                      // to a propose that prohibit the set from carrying out an auction i.e. a token that only the manager possesses
                      require(
                          componentWhiteList.areValidAddresses(_nextSet.getComponents()),
                          "Invalid component"
                      );
              
                      // Check that the proposed set natural unit is a multiple of current set natural unit, or vice versa.
                      // Done to make sure that when calculating token units there will are be rounding errors.
                      require(
                          naturalUnitsAreValid(currentSet, _nextSet),
                          "Invalid natural unit"
                      );
                  }
              
                  /**
                   * Calculates the maximum quantity of the currentSet that can be redeemed. This is defined
                   * by how many naturalUnits worth of the Set there are.
                   *
                   * @return   Maximum quantity of the current Set that can be redeemed
                   */
                  function calculateStartingSetQuantity()
                      internal
                      view
                      returns (uint256)
                  {
                      uint256 currentSetBalance = vault.getOwnerBalance(address(currentSet), address(this));
                      uint256 currentSetNaturalUnit = currentSet.naturalUnit();
              
                      // Rounds the redemption quantity to a multiple of the current Set natural unit
                      return currentSetBalance.sub(currentSetBalance.mod(currentSetNaturalUnit));
                  }
              
                  /**
                   * Signals to the Liquidator to initiate the rebalance.
                   *
                   * @param _nextSet                         Next set instance
                   * @param _startingCurrentSetQuantity      Amount of currentSets the rebalance is initiated with
                   * @param _liquidatorData                  Bytecode formatted data with liquidator-specific arguments
                   */
                  function liquidatorRebalancingStart(
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity,
                      bytes memory _liquidatorData
                  )
                      internal
                  {
                      liquidator.startRebalance(
                          currentSet,
                          _nextSet,
                          _startingCurrentSetQuantity,
                          _liquidatorData
                      );
                  }
              
                  /**
                   * Updates rebalance-related state parameters.
                   *
                   * @param _nextSet                    The Set to rebalance into
                   */
                  function transitionToRebalance(ISetToken _nextSet) internal {
                      nextSet = _nextSet;
                      rebalanceState = RebalancingLibrary.State.Rebalance;
                      rebalanceStartTime = block.timestamp;
                  }
              
                  /* ============ Private Functions ============ */
              
                  /**
                   * Check that the proposed set natural unit is a multiple of current set natural unit, or vice versa.
                   * Done to make sure that when calculating token units there will be no rounding errors.
                   *
                   * @param _currentSet                 The current base SetToken
                   * @param _nextSet                    The proposed SetToken
                   */
                  function naturalUnitsAreValid(
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      private
                      view
                      returns (bool)
                  {
                      uint256 currentNaturalUnit = _currentSet.naturalUnit();
                      uint256 nextSetNaturalUnit = _nextSet.naturalUnit();
              
                      return Math.max(currentNaturalUnit, nextSetNaturalUnit).mod(
                          Math.min(currentNaturalUnit, nextSetNaturalUnit)
                      ) == 0;
                  }
              }
              
              // File: contracts/core/tokens/RebalancingSetTokenV2.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              
              /**
               * @title RebalancingSetTokenV2
               * @author Set Protocol
               *
               * Implementation of Rebalancing Set token V2. Major improvements vs. V1 include:
               * - Decouple the Rebalancing Set state and rebalance state from the rebalance execution (e.g. auction)
               *   This allows us to rapidly iterate and build new liquidation mechanisms for rebalances.
               * - Proposals are removed in favor of starting an auction directly.
               * - The Set retains ability to fail an auction if the minimum fail time has elapsed.
               * - RebalanceAuctionModule execution should be backwards compatible with V1.
               * - Bidding and auction parameters state no longer live on this contract. They live on the liquidator
               *   BackwardsComptability is used to allow retrieving of previous supported states.
               * - Introduces entry and rebalance fees, where rebalance fees are configurable based on an external
               *   fee calculator contract
               */
              contract RebalancingSetTokenV2 is
                  ERC20,
                  ERC20Detailed,
                  Initializable,
                  RebalancingSetState,
                  BackwardCompatibility,
                  Issuance,
                  RebalancingStart,
                  RebalancingBid,
                  RebalancingSettlement,
                  RebalancingFailure
              {
              
                  /* ============ Constructor ============ */
              
                  /**
                   * Constructor function for Rebalancing Set Token
                   *
                   * addressConfig [factory, manager, liquidator, initialSet, componentWhiteList,
                   *                liquidatorWhiteList, feeRecipient, rebalanceFeeCalculator]
                   * [0]factory                   Factory used to create the Rebalancing Set
                   * [1]manager                   Address that is able to propose the next Set
                   * [2]liquidator                Address of the liquidator contract
                   * [3]initialSet                Initial set that collateralizes the Rebalancing set
                   * [4]componentWhiteList        Whitelist that nextSet components are checked against during propose
                   * [5]liquidatorWhiteList       Whitelist of valid liquidators
                   * [6]feeRecipient              Address that receives any incentive fees
                   * [7]rebalanceFeeCalculator    Address to retrieve rebalance fee during settlement
                   *
                   * uintConfig [initialUnitShares, naturalUnit, rebalanceInterval, rebalanceFailPeriod,
                   *             lastRebalanceTimestamp, entryFee]
                   * [0]initialUnitShares         Units of currentSet that equals one share
                   * [1]naturalUnit               The minimum multiple of Sets that can be issued or redeemed
                   * [2]rebalanceInterval:        Minimum amount of time between rebalances
                   * [3]rebalanceFailPeriod:      Time after auctionStart where something in the rebalance has gone wrong
                   * [4]lastRebalanceTimestamp:   Time of the last rebalance; Allows customized deployments
                   * [5]entryFee:                 Mint fee represented in a scaled decimal value (e.g. 100% = 1e18, 1% = 1e16)
                   *
                   * @param _addressConfig             List of configuration addresses
                   * @param _uintConfig                List of uint addresses
                   * @param _name                      The name of the new RebalancingSetTokenV2
                   * @param _symbol                    The symbol of the new RebalancingSetTokenV2
                   */
                  constructor(
                      address[8] memory _addressConfig,
                      uint256[6] memory _uintConfig,
                      string memory _name,
                      string memory _symbol
                  )
                      public
                      ERC20Detailed(
                          _name,
                          _symbol,
                          18
                      )
                  {
                      factory = IRebalancingSetFactory(_addressConfig[0]);
                      manager = _addressConfig[1];
                      liquidator = ILiquidator(_addressConfig[2]);
                      currentSet = ISetToken(_addressConfig[3]);
                      componentWhiteList = IWhiteList(_addressConfig[4]);
                      liquidatorWhiteList = IWhiteList(_addressConfig[5]);
                      feeRecipient = _addressConfig[6];
                      rebalanceFeeCalculator = IFeeCalculator(_addressConfig[7]);
              
                      unitShares = _uintConfig[0];
                      naturalUnit = _uintConfig[1];
                      rebalanceInterval = _uintConfig[2];
                      rebalanceFailPeriod = _uintConfig[3];
                      lastRebalanceTimestamp = _uintConfig[4];
                      entryFee = _uintConfig[5];
              
                      core = ICore(factory.core());
                      vault = IVault(core.vault());
                      rebalanceState = RebalancingLibrary.State.Default;
                  }
              
                  /*
                   * Intended to be called during creation by the RebalancingSetTokenFactory. Can only be initialized
                   * once. This implementation initializes the rebalance fee.
                   *
                   *
                   * @param _rebalanceFeeCalldata       Bytes encoded rebalance fee represented as a scaled percentage value
                   */
                  function initialize(
                      bytes calldata _rebalanceFeeCalldata
                  )
                      external
                      initializer
                  {
                      rebalanceFeeCalculator.initialize(_rebalanceFeeCalldata);
                  }
              
                 /* ============ External Functions ============ */
              
                  /*
                   * Initiates the rebalance in coordination with the Liquidator contract.
                   * In this step, we redeem the currentSet and pass relevant information
                   * to the liquidator.
                   *
                   * @param _nextSet                      The Set to rebalance into
                   * @param _liquidatorData               Bytecode formatted data with liquidator-specific arguments
                   *
                   * Can only be called if the rebalance interval has elapsed.
                   * Can only be called by manager.
                   */
                  function startRebalance(
                      ISetToken _nextSet,
                      bytes calldata _liquidatorData
                  )
                      external
                      onlyManager
                  {
                      RebalancingStart.validateStartRebalance(_nextSet);
              
                      uint256 startingCurrentSetQuantity = RebalancingStart.calculateStartingSetQuantity();
              
                      core.redeemInVault(address(currentSet), startingCurrentSetQuantity);
              
                      RebalancingStart.liquidatorRebalancingStart(_nextSet, startingCurrentSetQuantity, _liquidatorData);
              
                      RebalancingStart.transitionToRebalance(_nextSet);
              
                      emit RebalanceStarted(
                          address(currentSet),
                          address(nextSet),
                          rebalanceIndex,
                          startingCurrentSetQuantity
                      );
                  }
              
                  /*
                   * Get token inflows and outflows required for bid from the Liquidator.
                   *
                   * @param _quantity               The amount of currentSet to be rebalanced
                   * @return inflowUnitArray          Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray         Array of amount of tokens taken out of system in bid
                   */
                  function getBidPrice(
                      uint256 _quantity
                  )
                      public
                      view
                      returns (uint256[] memory, uint256[] memory)
                  {
                      RebalancingBid.validateGetBidPrice(_quantity);
              
                      return Rebalance.decomposeTokenFlowToBidPrice(
                          liquidator.getBidPrice(address(this), _quantity)
                      );
                  }
              
                  /*
                   * Place bid during rebalance auction.
                   *
                   * The intended caller is the RebalanceAuctionModule, which must be approved by Core.
                   * Call Flow:
                   * RebalanceAuctionModule -> RebalancingSetTokenV2 -> Liquidator
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   * @return combinedTokenArray       Array of token addresses invovled in rebalancing
                   * @return inflowUnitArray          Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray         Array of amount of tokens taken out of system in bid
                   */
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      returns (address[] memory, uint256[] memory, uint256[] memory)
                  {
                      RebalancingBid.validatePlaceBid(_quantity);
              
                      // Place bid and get back inflow and outflow arrays
                      Rebalance.TokenFlow memory tokenFlow = liquidator.placeBid(_quantity);
              
                      RebalancingBid.updateHasBiddedIfNecessary();
              
                      return Rebalance.decomposeTokenFlow(tokenFlow);
                  }
              
                  /*
                   * After a successful rebalance, the new Set is issued. If there is a rebalance fee,
                   * the fee is paid via inflation of the Rebalancing Set to the feeRecipient.
                   * Full issuance functionality is now returned to set owners.
                   *
                   * Anyone can call this function.
                   */
                  function settleRebalance()
                      external
                  {
                      RebalancingSettlement.validateRebalancingSettlement();
              
                      uint256 issueQuantity = RebalancingSettlement.calculateSetIssueQuantity(nextSet);
              
                      // Calculates fees and mints Rebalancing Set to the feeRecipient, increasing supply
                      (uint256 feePercent, uint256 feeQuantity) = RebalancingSettlement.handleFees();
              
                      uint256 newUnitShares = RebalancingSettlement.calculateNextSetNewUnitShares(issueQuantity);
              
                      // The unit shares must result in a quantity greater than the number of natural units outstanding
                      require(
                          newUnitShares > 0,
                          "Failed: unitshares is 0."
                      );
              
                      RebalancingSettlement.issueNextSet(issueQuantity);
              
                      liquidator.settleRebalance();
              
                      // Rebalance index is the current vs next rebalance
                      emit RebalanceSettled(
                          feeRecipient,
                          feeQuantity,
                          feePercent,
                          rebalanceIndex,
                          issueQuantity,
                          newUnitShares
                      );
              
                      RebalancingSettlement.transitionToDefault(newUnitShares);
              
                  }
              
                  /*
                   * Ends a rebalance if there are any signs that there is a failure.
                   * Possible failure reasons:
                   * 1. The rebalance has elapsed the failRebalancePeriod
                   * 2. The liquidator responds that the rebalance has failed
                   *
                   * Move to Drawdown state if bids have been placed. Reset to Default state if no bids placed.
                   */
                  function endFailedRebalance()
                      public
                  {
                      RebalancingFailure.validateFailRebalance();
              
                      RebalancingLibrary.State newRebalanceState = RebalancingFailure.getNewRebalanceState();
              
                      liquidator.endFailedRebalance();
              
                      RebalancingFailure.transitionToNewState(newRebalanceState);
                  }
              
                  /*
                   * Mint set token for given address. If there if is an entryFee, calculates the fee and mints
                   * the rebalancing SetToken to the feeRecipient.
                   *
                   * Can only be called by Core contract.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external
                  {
                      Issuance.validateMint();
              
                      uint256 issueQuantityNetOfFees = Issuance.handleEntryFees(_quantity);
              
                      ERC20._mint(_issuer, issueQuantityNetOfFees);
                  }
              
                  /*
                   * Burn set token for given address. Can only be called by authorized contracts.
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external
                  {
                      Issuance.validateBurn();
              
                      ERC20._burn(_from, _quantity);
                  }
              
                  /* ============ Backwards Compatability ============ */
              
                  /*
                   * Alias for endFailedRebalance
                   */
                  function endFailedAuction() external {
                      endFailedRebalance();
                  }
              }
              
              // File: contracts/core/tokens/RebalancingSetTokenV3.sol
              
              /*
                  Copyright 2020 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              /**
               * @title RebalancingSetTokenV3
               * @author Set Protocol
               *
               * Implementation of Rebalancing Set token V2. Major improvements vs. V2 include:
               * - Separating incentive fees from the settlement process.
               */
              contract RebalancingSetTokenV3 is
                  IncentiveFee,
                  RebalancingSetTokenV2
              {
                  /* ============ Constructor ============ */
              
                  /**
                   * Constructor function for Rebalancing Set Token
                   *
                   * addressConfig [factory, manager, liquidator, initialSet, componentWhiteList,
                   *                liquidatorWhiteList, feeRecipient, rebalanceFeeCalculator]
                   * [0]factory                   Factory used to create the Rebalancing Set
                   * [1]manager                   Address that is able to propose the next Set
                   * [2]liquidator                Address of the liquidator contract
                   * [3]initialSet                Initial set that collateralizes the Rebalancing set
                   * [4]componentWhiteList        Whitelist that nextSet components are checked against during propose
                   * [5]liquidatorWhiteList       Whitelist of valid liquidators
                   * [6]feeRecipient              Address that receives any incentive fees
                   * [7]rebalanceFeeCalculator    Address to retrieve rebalance fee during settlement
                   *
                   * uintConfig [initialUnitShares, naturalUnit, rebalanceInterval, rebalanceFailPeriod,
                   *             lastRebalanceTimestamp, entryFee]
                   * [0]initialUnitShares         Units of currentSet that equals one share
                   * [1]naturalUnit               The minimum multiple of Sets that can be issued or redeemed
                   * [2]rebalanceInterval:        Minimum amount of time between rebalances
                   * [3]rebalanceFailPeriod:      Time after auctionStart where something in the rebalance has gone wrong
                   * [4]lastRebalanceTimestamp:   Time of the last rebalance; Allows customized deployments
                   * [5]entryFee:                 Mint fee represented in a scaled decimal value (e.g. 100% = 1e18, 1% = 1e16)
                   *
                   * @param _addressConfig             List of configuration addresses
                   * @param _uintConfig                List of uint addresses
                   * @param _name                      The name of the new RebalancingSetTokenV2
                   * @param _symbol                    The symbol of the new RebalancingSetTokenV2
                   */
                  constructor(
                      address[8] memory _addressConfig,
                      uint256[6] memory _uintConfig,
                      string memory _name,
                      string memory _symbol
                  )
                      public
                      RebalancingSetTokenV2(
                          _addressConfig,
                          _uintConfig,
                          _name,
                          _symbol
                      )
                  {}
              
                  /*
                   * Overrides the RebalancingSetTokenV2 settleRebalance function.
                   *
                   * After a successful rebalance, the new Set is issued.
                   * Full issuance functionality is now returned to set owners. No fees are captured.
                   *
                   * Anyone can call this function.
                   */
                  function settleRebalance()
                      external
                  {
                      // It can only be callable in the Default state
                      RebalancingSettlement.validateRebalancingSettlement();
              
                      uint256 issueQuantity = RebalancingSettlement.calculateSetIssueQuantity(nextSet);
                      uint256 newUnitShares = RebalancingSettlement.calculateNextSetNewUnitShares(issueQuantity);
              
                      validateUnitShares(newUnitShares);
              
                      RebalancingSettlement.issueNextSet(issueQuantity);
              
                      liquidator.settleRebalance();
              
                      emit RebalanceSettled(
                          address(0),      // No longer used
                          0,               // No longer used
                          0,               // No longer used
                          rebalanceIndex,  // Current Rebalance index
                          issueQuantity,
                          newUnitShares
                      );
              
                      RebalancingSettlement.transitionToDefault(newUnitShares);
                  }
              
                  /*
                   * During the Default stage, the incentive / rebalance Fee can be triggered. This will
                   * retrieve the current inflation fee from the fee calulator and mint the according
                   * inflation to the feeRecipient. The unit shares is then adjusted based on the new
                   * supply.
                   *
                   * Anyone can call this function.
                   */
                  function actualizeFee()
                      public
                  {
                      IncentiveFee.validateFeeActualization();
              
                      // Calculates fees and mints Rebalancing Set to the feeRecipient, increasing supply
                      (uint256 feePercent, uint256 feeQuantity) = IncentiveFee.handleFees();
              
                      // The minting of new supply changes the unit Shares
                      uint256 newUnitShares = IncentiveFee.calculateNewUnitShares();
              
                      validateUnitShares(newUnitShares);
              
                      // Set the new unit shares
                      unitShares = newUnitShares;
              
                      // Emit IncentiveFeePaid event
                      emit IncentiveFeePaid(
                          feeRecipient,
                          feeQuantity,
                          feePercent,
                          newUnitShares
                      );
                  }
              
                  /*
                   * Accrue any fees then adjust fee parameters on feeCalculator. Only callable by manager.
                   *
                   * @param  _newFeeData       Fee type and new streaming fee encoded in bytes
                   */
                  function adjustFee(
                      bytes calldata _newFeeData
                  )
                      external
                      onlyManager
                  {
                      actualizeFee();
              
                      rebalanceFeeCalculator.adjustFee(_newFeeData);
                  }
              
                  /* ============ V3 Internal Functions ============ */
              
                  /*
                   * The unit shares must result in a quantity greater than the number of natural units outstanding.
                   * In other words, it must be greater than 0
                   */
                  function validateUnitShares(uint256 _newUnitShares) internal view {
                      require(
                          _newUnitShares > 0,
                          "Unitshares is 0"
                      );
                  }
              }

              File 2 of 8: Vault
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Ownable
               * @dev The Ownable contract has an owner address, and provides basic authorization control
               * functions, this simplifies the implementation of "user permissions".
               */
              contract Ownable {
                  address private _owner;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                   * account.
                   */
                  constructor () internal {
                      _owner = msg.sender;
                      emit OwnershipTransferred(address(0), _owner);
                  }
              
                  /**
                   * @return the address of the owner.
                   */
                  function owner() public view returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(isOwner());
                      _;
                  }
              
                  /**
                   * @return true if `msg.sender` is the owner of the contract.
                   */
                  function isOwner() public view returns (bool) {
                      return msg.sender == _owner;
                  }
              
                  /**
                   * @dev Allows the current owner to relinquish control of the contract.
                   * It will not be possible to call the functions with the `onlyOwner`
                   * modifier anymore.
                   * @notice Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = address(0);
                  }
              
                  /**
                   * @dev Allows the current owner to transfer control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function transferOwnership(address newOwner) public onlyOwner {
                      _transferOwnership(newOwner);
                  }
              
                  /**
                   * @dev Transfers control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function _transferOwnership(address newOwner) internal {
                      require(newOwner != address(0));
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              // File: contracts/lib/AddressArrayUtils.sol
              
              // Pulled in from Cryptofin Solidity package in order to control Solidity compiler version
              // https://github.com/cryptofinlabs/cryptofin-solidity/blob/master/contracts/array-utils/AddressArrayUtils.sol
              
              pragma solidity 0.5.7;
              
              
              library AddressArrayUtils {
              
                  /**
                   * Finds the index of the first occurrence of the given element.
                   * @param A The input array to search
                   * @param a The value to find
                   * @return Returns (index and isIn) for the first occurrence starting from index 0
                   */
                  function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length; i++) {
                          if (A[i] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                  * Returns true if the value is present in the list. Uses indexOf internally.
                  * @param A The input array to search
                  * @param a The value to find
                  * @return Returns isIn for the first occurrence starting from index 0
                  */
                  function contains(address[] memory A, address a) internal pure returns (bool) {
                      bool isIn;
                      (, isIn) = indexOf(A, a);
                      return isIn;
                  }
              
                  /// @return Returns index and isIn for the first occurrence starting from
                  /// end
                  function indexOfFromEnd(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = length; i > 0; i--) {
                          if (A[i - 1] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                   * Returns the combination of the two arrays
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A extended by B
                   */
                  function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 aLength = A.length;
                      uint256 bLength = B.length;
                      address[] memory newAddresses = new address[](aLength + bLength);
                      for (uint256 i = 0; i < aLength; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = 0; j < bLength; j++) {
                          newAddresses[aLength + j] = B[j];
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the array with a appended to A.
                   * @param A The first array
                   * @param a The value to append
                   * @return Returns A appended by a
                   */
                  function append(address[] memory A, address a) internal pure returns (address[] memory) {
                      address[] memory newAddresses = new address[](A.length + 1);
                      for (uint256 i = 0; i < A.length; i++) {
                          newAddresses[i] = A[i];
                      }
                      newAddresses[A.length] = a;
                      return newAddresses;
                  }
              
                  /**
                   * Returns the combination of two storage arrays.
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A appended by a
                   */
                  function sExtend(address[] storage A, address[] storage B) internal {
                      uint256 length = B.length;
                      for (uint256 i = 0; i < length; i++) {
                          A.push(B[i]);
                      }
                  }
              
                  /**
                   * Returns the intersection of two arrays. Arrays are treated as collections, so duplicates are kept.
                   * @param A The first array
                   * @param B The second array
                   * @return The intersection of the two arrays
                   */
                  function intersect(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 newLength = 0;
                      for (uint256 i = 0; i < length; i++) {
                          if (contains(B, A[i])) {
                              includeMap[i] = true;
                              newLength++;
                          }
                      }
                      address[] memory newAddresses = new address[](newLength);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the union of the two arrays. Order is not guaranteed.
                   * @param A The first array
                   * @param B The second array
                   * @return The union of the two arrays
                   */
                  function union(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      address[] memory leftDifference = difference(A, B);
                      address[] memory rightDifference = difference(B, A);
                      address[] memory intersection = intersect(A, B);
                      return extend(leftDifference, extend(intersection, rightDifference));
                  }
              
                  /**
                   * Alternate implementation
                   * Assumes there are no duplicates
                   */
                  function unionB(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      bool[] memory includeMap = new bool[](A.length + B.length);
                      uint256 count = 0;
                      for (uint256 i = 0; i < A.length; i++) {
                          includeMap[i] = true;
                          count++;
                      }
                      for (uint256 j = 0; j < B.length; j++) {
                          if (!contains(A, B[j])) {
                              includeMap[A.length + j] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 k = 0;
                      for (uint256 m = 0; m < A.length; m++) {
                          if (includeMap[m]) {
                              newAddresses[k] = A[m];
                              k++;
                          }
                      }
                      for (uint256 n = 0; n < B.length; n++) {
                          if (includeMap[A.length + n]) {
                              newAddresses[k] = B[n];
                              k++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Computes the difference of two arrays. Assumes there are no duplicates.
                   * @param A The first array
                   * @param B The second array
                   * @return The difference of the two arrays
                   */
                  function difference(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 count = 0;
                      // First count the new length because can't push for in-memory arrays
                      for (uint256 i = 0; i < length; i++) {
                          address e = A[i];
                          if (!contains(B, e)) {
                              includeMap[i] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                  * @dev Reverses storage array in place
                  */
                  function sReverse(address[] storage A) internal {
                      address t;
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length / 2; i++) {
                          t = A[i];
                          A[i] = A[A.length - i - 1];
                          A[A.length - i - 1] = t;
                      }
                  }
              
                  /**
                  * Removes specified index from array
                  * Resulting ordering is not guaranteed
                  * @return Returns the new array and the removed entry
                  */
                  function pop(address[] memory A, uint256 index)
                      internal
                      pure
                      returns (address[] memory, address)
                  {
                      uint256 length = A.length;
                      address[] memory newAddresses = new address[](length - 1);
                      for (uint256 i = 0; i < index; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = index + 1; j < length; j++) {
                          newAddresses[j - 1] = A[j];
                      }
                      return (newAddresses, A[index]);
                  }
              
                  /**
                   * @return Returns the new array
                   */
                  function remove(address[] memory A, address a)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert();
                      } else {
                          (address[] memory _A,) = pop(A, index);
                          return _A;
                      }
                  }
              
                  function sPop(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      for (uint256 i = index; i < length - 1; i++) {
                          A[i] = A[i + 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                  * Deletes address at index and fills the spot with the last address.
                  * Order is not preserved.
                  * @return Returns the removed entry
                  */
                  function sPopCheap(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      if (index != length - 1) {
                          A[index] = A[length - 1];
                          delete A[length - 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                   * Deletes address at index. Works by swapping it with the last address, then deleting.
                   * Order is not preserved
                   * @param A Storage array to remove from
                   */
                  function sRemoveCheap(address[] storage A, address a) internal {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert("Error: entry not found");
                      } else {
                          sPopCheap(A, index);
                          return;
                      }
                  }
              
                  /**
                   * Returns whether or not there's a duplicate. Runs in O(n^2).
                   * @param A Array to search
                   * @return Returns true if duplicate, false otherwise
                   */
                  function hasDuplicate(address[] memory A) internal pure returns (bool) {
                      if (A.length == 0) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length - 1; i++) {
                          for (uint256 j = i + 1; j < A.length; j++) {
                              if (A[i] == A[j]) {
                                  return true;
                              }
                          }
                      }
                      return false;
                  }
              
                  /**
                   * Returns whether the two arrays are equal.
                   * @param A The first array
                   * @param B The second array
                   * @return True is the arrays are equal, false if not.
                   */
                  function isEqual(address[] memory A, address[] memory B) internal pure returns (bool) {
                      if (A.length != B.length) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length; i++) {
                          if (A[i] != B[i]) {
                              return false;
                          }
                      }
                      return true;
                  }
              
                  /**
                   * Returns the elements indexed at indexArray.
                   * @param A The array to index
                   * @param indexArray The array to use to index
                   * @return Returns array containing elements indexed at indexArray
                   */
                  function argGet(address[] memory A, uint256[] memory indexArray)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      address[] memory array = new address[](indexArray.length);
                      for (uint256 i = 0; i < indexArray.length; i++) {
                          array[i] = A[indexArray[i]];
                      }
                      return array;
                  }
              
              }
              
              // File: contracts/lib/TimeLockUpgrade.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title TimeLockUpgrade
               * @author Set Protocol
               *
               * The TimeLockUpgrade contract contains a modifier for handling minimum time period updates
               */
              contract TimeLockUpgrade is
                  Ownable
              {
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  // Timelock Upgrade Period in seconds
                  uint256 public timeLockPeriod;
              
                  // Mapping of upgradable units and initialized timelock
                  mapping(bytes32 => uint256) public timeLockedUpgrades;
              
                  /* ============ Events ============ */
              
                  event UpgradeRegistered(
                      bytes32 _upgradeHash,
                      uint256 _timestamp
                  );
              
                  /* ============ Modifiers ============ */
              
                  modifier timeLockUpgrade() {
                      // If the time lock period is 0, then allow non-timebound upgrades.
                      // This is useful for initialization of the protocol and for testing.
                      if (timeLockPeriod == 0) {
                          _;
              
                          return;
                      }
              
                      // The upgrade hash is defined by the hash of the transaction call data,
                      // which uniquely identifies the function as well as the passed in arguments.
                      bytes32 upgradeHash = keccak256(
                          abi.encodePacked(
                              msg.data
                          )
                      );
              
                      uint256 registrationTime = timeLockedUpgrades[upgradeHash];
              
                      // If the upgrade hasn't been registered, register with the current time.
                      if (registrationTime == 0) {
                          timeLockedUpgrades[upgradeHash] = block.timestamp;
              
                          emit UpgradeRegistered(
                              upgradeHash,
                              block.timestamp
                          );
              
                          return;
                      }
              
                      require(
                          block.timestamp >= registrationTime.add(timeLockPeriod),
                          "TimeLockUpgrade: Time lock period must have elapsed."
                      );
              
                      // Reset the timestamp to 0
                      timeLockedUpgrades[upgradeHash] = 0;
              
                      // Run the rest of the upgrades
                      _;
                  }
              
                  /* ============ Function ============ */
              
                  /**
                   * Change timeLockPeriod period. Generally called after initially settings have been set up.
                   *
                   * @param  _timeLockPeriod   Time in seconds that upgrades need to be evaluated before execution
                   */
                  function setTimeLockPeriod(
                      uint256 _timeLockPeriod
                  )
                      external
                      onlyOwner
                  {
                      // Only allow setting of the timeLockPeriod if the period is greater than the existing
                      require(
                          _timeLockPeriod > timeLockPeriod,
                          "TimeLockUpgrade: New period must be greater than existing"
                      );
              
                      timeLockPeriod = _timeLockPeriod;
                  }
              }
              
              // File: contracts/lib/Authorizable.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              /**
               * @title Authorizable
               * @author Set Protocol
               *
               * The Authorizable contract is an inherited contract that sets permissions on certain function calls
               * through the onlyAuthorized modifier. Permissions can be managed only by the Owner of the contract.
               */
              contract Authorizable is
                  Ownable,
                  TimeLockUpgrade
              {
                  using SafeMath for uint256;
                  using AddressArrayUtils for address[];
              
                  /* ============ State Variables ============ */
              
                  // Mapping of addresses to bool indicator of authorization
                  mapping (address => bool) public authorized;
              
                  // Array of authorized addresses
                  address[] public authorities;
              
                  /* ============ Modifiers ============ */
              
                  // Only authorized addresses can invoke functions with this modifier.
                  modifier onlyAuthorized {
                      require(
                          authorized[msg.sender],
                          "Authorizable.onlyAuthorized: Sender not included in authorities"
                      );
                      _;
                  }
              
                  /* ============ Events ============ */
              
                  // Event emitted when new address is authorized.
                  event AddressAuthorized (
                      address indexed authAddress,
                      address authorizedBy
                  );
              
                  // Event emitted when address is deauthorized.
                  event AuthorizedAddressRemoved (
                      address indexed addressRemoved,
                      address authorizedBy
                  );
              
                  /* ============ Setters ============ */
              
                  /**
                   * Add authorized address to contract. Can only be set by owner.
                   *
                   * @param  _authTarget   The address of the new authorized contract
                   */
              
                  function addAuthorizedAddress(address _authTarget)
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      // Require that address is not already authorized
                      require(
                          !authorized[_authTarget],
                          "Authorizable.addAuthorizedAddress: Address already registered"
                      );
              
                      // Set address authority to true
                      authorized[_authTarget] = true;
              
                      // Add address to authorities array
                      authorities.push(_authTarget);
              
                      // Emit authorized address event
                      emit AddressAuthorized(
                          _authTarget,
                          msg.sender
                      );
                  }
              
                  /**
                   * Remove authorized address from contract. Can only be set by owner.
                   *
                   * @param  _authTarget   The address to be de-permissioned
                   */
              
                  function removeAuthorizedAddress(address _authTarget)
                      external
                      onlyOwner
                  {
                      // Require address is authorized
                      require(
                          authorized[_authTarget],
                          "Authorizable.removeAuthorizedAddress: Address not authorized"
                      );
              
                      // Delete address from authorized mapping
                      authorized[_authTarget] = false;
              
                      authorities = authorities.remove(_authTarget);
              
                      // Emit AuthorizedAddressRemoved event.
                      emit AuthorizedAddressRemoved(
                          _authTarget,
                          msg.sender
                      );
                  }
              
                  /* ============ Getters ============ */
              
                  /**
                   * Get array of authorized addresses.
                   *
                   * @return address[]   Array of authorized addresses
                   */
                  function getAuthorizedAddresses()
                      external
                      view
                      returns (address[] memory)
                  {
                      // Return array of authorized addresses
                      return authorities;
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/lib/IERC20.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title IERC20
               * @author Set Protocol
               *
               * Interface for using ERC20 Tokens. This interface is needed to interact with tokens that are not
               * fully ERC20 compliant and return something other than true on successful transfers.
               */
              interface IERC20 {
                  function balanceOf(
                      address _owner
                  )
                      external
                      view
                      returns (uint256);
              
                  function allowance(
                      address _owner,
                      address _spender
                  )
                      external
                      view
                      returns (uint256);
              
                  function transfer(
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  function transferFrom(
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  function approve(
                      address _spender,
                      uint256 _quantity
                  )
                      external
                      returns (bool);
              }
              
              // File: contracts/lib/ERC20Wrapper.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title ERC20Wrapper
               * @author Set Protocol
               *
               * This library contains functions for interacting wtih ERC20 tokens, even those not fully compliant.
               * For all functions we will only accept tokens that return a null or true value, any other values will
               * cause the operation to revert.
               */
              library ERC20Wrapper {
              
                  // ============ Internal Functions ============
              
                  /**
                   * Check balance owner's balance of ERC20 token
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The owner who's balance is being checked
                   * @return  uint256        The _owner's amount of tokens
                   */
                  function balanceOf(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256)
                  {
                      return IERC20(_token).balanceOf(_owner);
                  }
              
                  /**
                   * Checks spender's allowance to use token's on owner's behalf.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The token owner address
                   * @param  _spender        The address the allowance is being checked on
                   * @return  uint256        The spender's allowance on behalf of owner
                   */
                  function allowance(
                      address _token,
                      address _owner,
                      address _spender
                  )
                      internal
                      view
                      returns (uint256)
                  {
                      return IERC20(_token).allowance(_owner, _spender);
                  }
              
                  /**
                   * Transfers tokens from an address. Handle's tokens that return true or null.
                   * If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer to
                   * @param  _quantity       The amount of tokens to transfer
                   */
                  function transfer(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external
                  {
                      IERC20(_token).transfer(_to, _quantity);
              
                      // Check that transfer returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.transfer: Bad return value"
                      );
                  }
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Handle's tokens that return true or null. If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function transferFrom(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external
                  {
                      IERC20(_token).transferFrom(_from, _to, _quantity);
              
                      // Check that transferFrom returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.transferFrom: Bad return value"
                      );
                  }
              
                  /**
                   * Grants spender ability to spend on owner's behalf.
                   * Handle's tokens that return true or null. If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _spender        The address to approve for transfer
                   * @param  _quantity       The amount of tokens to approve spender for
                   */
                  function approve(
                      address _token,
                      address _spender,
                      uint256 _quantity
                  )
                      internal
                  {
                      IERC20(_token).approve(_spender, _quantity);
              
                      // Check that approve returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.approve: Bad return value"
                      );
                  }
              
                  /**
                   * Ensure's the owner has granted enough allowance for system to
                   * transfer tokens.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The address of the token owner
                   * @param  _spender        The address to grant/check allowance for
                   * @param  _quantity       The amount to see if allowed for
                   */
                  function ensureAllowance(
                      address _token,
                      address _owner,
                      address _spender,
                      uint256 _quantity
                  )
                      internal
                  {
                      uint256 currentAllowance = allowance(_token, _owner, _spender);
                      if (currentAllowance < _quantity) {
                          approve(
                              _token,
                              _spender,
                              CommonMath.maxUInt256()
                          );
                      }
                  }
              
                  // ============ Private Functions ============
              
                  /**
                   * Checks the return value of the previous function up to 32 bytes. Returns true if the previous
                   * function returned 0 bytes or 1.
                   */
                  function checkSuccess(
                  )
                      private
                      pure
                      returns (bool)
                  {
                      // default to failure
                      uint256 returnValue = 0;
              
                      assembly {
                          // check number of bytes returned from last function call
                          switch returndatasize
              
                          // no bytes returned: assume success
                          case 0x0 {
                              returnValue := 1
                          }
              
                          // 32 bytes returned
                          case 0x20 {
                              // copy 32 bytes into scratch space
                              returndatacopy(0x0, 0x0, 0x20)
              
                              // load those bytes into returnValue
                              returnValue := mload(0x0)
                          }
              
                          // not sure what was returned: dont mark as success
                          default { }
                      }
              
                      // check if returned value is one or nothing
                      return returnValue == 1;
                  }
              }
              
              // File: contracts/core/Vault.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              /**
               * @title Vault
               * @author Set Protocol
               *
               * The vault contract is responsible for holding all funds and keeping track of the
               * fund state and which Sets own which funds.
               *
               */
              
              contract Vault is
                  Authorizable
              {
                  // Use SafeMath library for all uint256 arithmetic
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  // Mapping of token address to map of owner or Set address to balance.
                  // Example of mapping below:
                  // +--------------+---------------------+--------+
                  // | TokenAddress | Set OR User Address | Amount |
                  // +--------------+---------------------+--------+
                  // | TokenA       | User 0x123          |    500 |
                  // |              | User 0xABC          |    300 |
                  // |              | Set  0x456          |   1000 |
                  // | TokenB       | User 0xDEF          |    100 |
                  // |              | Set  0xSET          |    700 |
                  // +--------------+---------------------+--------+
                  mapping (address => mapping (address => uint256)) public balances;
              
                  /* ============ External Functions ============ */
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer token to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function withdrawTo(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      public
                      onlyAuthorized
                  {
                      if (_quantity > 0) {
                          // Retrieve current balance of token for the vault
                          uint256 existingVaultBalance = ERC20Wrapper.balanceOf(
                              _token,
                              address(this)
                          );
              
                          // Call specified ERC20 token contract to transfer tokens from Vault to user
                          ERC20Wrapper.transfer(
                              _token,
                              _to,
                              _quantity
                          );
              
                          // Verify transfer quantity is reflected in balance
                          uint256 newVaultBalance = ERC20Wrapper.balanceOf(
                              _token,
                              address(this)
                          );
                          // Check to make sure current balances are as expected
                          require(
                              newVaultBalance == existingVaultBalance.sub(_quantity),
                              "Vault.withdrawTo: Invalid post withdraw balance"
                          );
                      }
                  }
              
                  /*
                   * Increment quantity owned of a token for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to attribute to owner
                   */
                  function incrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      public
                      onlyAuthorized
                  {
                      if (_quantity > 0) {
                          // Increment balances state variable adding _quantity to user's token amount
                          balances[_token][_owner] = balances[_token][_owner].add(_quantity);
                      }
                  }
              
                  /*
                   * Decrement quantity owned of a token for a given address. Can only
                   * be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to deattribute to owner
                   */
                  function decrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      public
                      onlyAuthorized
                  {
                      // Require that user has enough unassociated tokens to withdraw tokens or issue Set
                      require(
                          balances[_token][_owner] >= _quantity,
                          "Vault.decrementTokenOwner: Insufficient token balance"
                      );
              
                      if (_quantity > 0) {
                          // Decrement balances state variable subtracting _quantity to user's token amount
                          balances[_token][_owner] = balances[_token][_owner].sub(_quantity);
                      }
                  }
              
                  /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _token          Address of token being transferred
                   * @param  _from           Address token being transferred from
                   * @param  _to             Address token being transferred to
                   * @param  _quantity       Amount of tokens being transferred
                   */
              
                  function transferBalance(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      public
                      onlyAuthorized
                  {
                      if (_quantity > 0) {
                          // Require that user has enough unassociated tokens to withdraw tokens or issue Set
                          require(
                              balances[_token][_from] >= _quantity,
                              "Vault.transferBalance: Insufficient token balance"
                          );
              
                          // Decrement balances state variable subtracting _quantity to user's token amount
                          balances[_token][_from] = balances[_token][_from].sub(_quantity);
              
                          // Increment balances state variable adding _quantity to user's token amount
                          balances[_token][_to] = balances[_token][_to].add(_quantity);
                      }
                  }
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _to              The address of the recipient
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchWithdrawTo(
                      address[] calldata _tokens,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyAuthorized
                  {
                      // Storing token count to local variable to save on invocation
                      uint256 tokenCount = _tokens.length;
              
                      // Confirm and empty _tokens array is not passed
                      require(
                          tokenCount > 0,
                          "Vault.batchWithdrawTo: Tokens must not be empty"
                      );
              
                      // Confirm there is one quantity for every token address
                      require(
                          tokenCount == _quantities.length,
                          "Vault.batchWithdrawTo: Tokens and quantities lengths mismatch"
                      );
              
                      for (uint256 i = 0; i < tokenCount; i++) {
                          withdrawTo(
                              _tokens[i],
                              _to,
                              _quantities[i]
                          );
                      }
                  }
              
                  /*
                   * Increment quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyAuthorized
                  {
                      // Storing token count to local variable to save on invocation
                      uint256 tokenCount = _tokens.length;
              
                      // Confirm and empty _tokens array is not passed
                      require(
                          tokenCount > 0,
                          "Vault.batchIncrementTokenOwner: Tokens must not be empty"
                      );
              
                      // Confirm there is one quantity for every token address
                      require(
                          tokenCount == _quantities.length,
                          "Vault.batchIncrementTokenOwner: Tokens and quantities lengths mismatch"
                      );
              
                      for (uint256 i = 0; i < tokenCount; i++) {
                          incrementTokenOwner(
                              _tokens[i],
                              _owner,
                              _quantities[i]
                          );
                      }
                  }
              
                  /*
                   * Decrements quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyAuthorized
                  {
                      // Storing token count to local variable to save on invocation
                      uint256 tokenCount = _tokens.length;
              
                      // Confirm and empty _tokens array is not passed
                      require(
                          tokenCount > 0,
                          "Vault.batchDecrementTokenOwner: Tokens must not be empty"
                      );
              
                      // Confirm there is one quantity for every token address
                      require(
                          tokenCount == _quantities.length,
                          "Vault.batchDecrementTokenOwner: Tokens and quantities lengths mismatch"
                      );
              
                      for (uint256 i = 0; i < tokenCount; i++) {
                          decrementTokenOwner(
                              _tokens[i],
                              _owner,
                              _quantities[i]
                          );
                      }
                  }
              
                  /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalance(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyAuthorized
                  {
                      // Storing token count to local variable to save on invocation
                      uint256 tokenCount = _tokens.length;
              
                      // Confirm and empty _tokens array is not passed
                      require(
                          tokenCount > 0,
                          "Vault.batchTransferBalance: Tokens must not be empty"
                      );
              
                      // Confirm there is one quantity for every token address
                      require(
                          tokenCount == _quantities.length,
                          "Vault.batchTransferBalance: Tokens and quantities lengths mismatch"
                      );
              
                      for (uint256 i = 0; i < tokenCount; i++) {
                          transferBalance(
                              _tokens[i],
                              _from,
                              _to,
                              _quantities[i]
                          );
                      }
                  }
              
                  /*
                   * Get balance of particular contract for owner.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   */
                  function getOwnerBalance(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256)
                  {
                      // Return owners token balance
                      return balances[_token][_owner];
                  }
              }

              File 3 of 8: SetToken
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title ERC20 interface
               * @dev see https://eips.ethereum.org/EIPS/eip-20
               */
              interface IERC20 {
                  function transfer(address to, uint256 value) external returns (bool);
              
                  function approve(address spender, uint256 value) external returns (bool);
              
                  function transferFrom(address from, address to, uint256 value) external returns (bool);
              
                  function totalSupply() external view returns (uint256);
              
                  function balanceOf(address who) external view returns (uint256);
              
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
              
              pragma solidity ^0.5.2;
              
              
              /**
               * @title ERC20Detailed token
               * @dev The decimals are only for visualization purposes.
               * All the operations are done using the smallest and indivisible token unit,
               * just as on Ethereum all the operations are done in wei.
               */
              contract ERC20Detailed is IERC20 {
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
              
                  constructor (string memory name, string memory symbol, uint8 decimals) public {
                      _name = name;
                      _symbol = symbol;
                      _decimals = decimals;
                  }
              
                  /**
                   * @return the name of the token.
                   */
                  function name() public view returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @return the symbol of the token.
                   */
                  function symbol() public view returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @return the number of decimals of the token.
                   */
                  function decimals() public view returns (uint8) {
                      return _decimals;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
              
              pragma solidity ^0.5.2;
              
              
              
              /**
               * @title Standard ERC20 token
               *
               * @dev Implementation of the basic standard token.
               * https://eips.ethereum.org/EIPS/eip-20
               * Originally based on code by FirstBlood:
               * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
               *
               * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
               * all accounts just by listening to said events. Note that this isn't required by the specification, and other
               * compliant implementations may not do it.
               */
              contract ERC20 is IERC20 {
                  using SafeMath for uint256;
              
                  mapping (address => uint256) private _balances;
              
                  mapping (address => mapping (address => uint256)) private _allowed;
              
                  uint256 private _totalSupply;
              
                  /**
                   * @dev Total number of tokens in existence
                   */
                  function totalSupply() public view returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev Gets the balance of the specified address.
                   * @param owner The address to query the balance of.
                   * @return A uint256 representing the amount owned by the passed address.
                   */
                  function balanceOf(address owner) public view returns (uint256) {
                      return _balances[owner];
                  }
              
                  /**
                   * @dev Function to check the amount of tokens that an owner allowed to a spender.
                   * @param owner address The address which owns the funds.
                   * @param spender address The address which will spend the funds.
                   * @return A uint256 specifying the amount of tokens still available for the spender.
                   */
                  function allowance(address owner, address spender) public view returns (uint256) {
                      return _allowed[owner][spender];
                  }
              
                  /**
                   * @dev Transfer token to a specified address
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function transfer(address to, uint256 value) public returns (bool) {
                      _transfer(msg.sender, to, value);
                      return true;
                  }
              
                  /**
                   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                   * Beware that changing an allowance with this method brings the risk that someone may use both the old
                   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
                   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to be spent.
                   */
                  function approve(address spender, uint256 value) public returns (bool) {
                      _approve(msg.sender, spender, value);
                      return true;
                  }
              
                  /**
                   * @dev Transfer tokens from one address to another.
                   * Note that while this function emits an Approval event, this is not required as per the specification,
                   * and other compliant implementations may not emit the event.
                   * @param from address The address which you want to send tokens from
                   * @param to address The address which you want to transfer to
                   * @param value uint256 the amount of tokens to be transferred
                   */
                  function transferFrom(address from, address to, uint256 value) public returns (bool) {
                      _transfer(from, to, value);
                      _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
                      return true;
                  }
              
                  /**
                   * @dev Increase the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To increment
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param addedValue The amount of tokens to increase the allowance by.
                   */
                  function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
                      return true;
                  }
              
                  /**
                   * @dev Decrease the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To decrement
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param subtractedValue The amount of tokens to decrease the allowance by.
                   */
                  function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
                      return true;
                  }
              
                  /**
                   * @dev Transfer token for a specified addresses
                   * @param from The address to transfer from.
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function _transfer(address from, address to, uint256 value) internal {
                      require(to != address(0));
              
                      _balances[from] = _balances[from].sub(value);
                      _balances[to] = _balances[to].add(value);
                      emit Transfer(from, to, value);
                  }
              
                  /**
                   * @dev Internal function that mints an amount of the token and assigns it to
                   * an account. This encapsulates the modification of balances such that the
                   * proper events are emitted.
                   * @param account The account that will receive the created tokens.
                   * @param value The amount that will be created.
                   */
                  function _mint(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.add(value);
                      _balances[account] = _balances[account].add(value);
                      emit Transfer(address(0), account, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account.
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burn(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.sub(value);
                      _balances[account] = _balances[account].sub(value);
                      emit Transfer(account, address(0), value);
                  }
              
                  /**
                   * @dev Approve an address to spend another addresses' tokens.
                   * @param owner The address that owns the tokens.
                   * @param spender The address that will spend the tokens.
                   * @param value The number of tokens that can be spent.
                   */
                  function _approve(address owner, address spender, uint256 value) internal {
                      require(spender != address(0));
                      require(owner != address(0));
              
                      _allowed[owner][spender] = value;
                      emit Approval(owner, spender, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account, deducting from the sender's allowance for said account. Uses the
                   * internal burn function.
                   * Emits an Approval event (reflecting the reduced allowance).
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burnFrom(address account, uint256 value) internal {
                      _burn(account, value);
                      _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
                  }
              }
              
              // File: contracts/lib/CommonValidationsLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              library CommonValidationsLibrary {
              
                  /**
                   * Ensures that an address array is not empty.
                   *
                   * @param  _addressArray       Address array input
                   */
                  function validateNonEmpty(
                      address[] calldata _addressArray
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length > 0,
                          "Address array length must be > 0"
                      );
                  }
              
                  /**
                   * Ensures that an address array and uint256 array are equal length
                   *
                   * @param  _addressArray       Address array input
                   * @param  _uint256Array       Uint256 array input
                   */
                  function validateEqualLength(
                      address[] calldata _addressArray,
                      uint256[] calldata _uint256Array
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length == _uint256Array.length,
                          "Input length mismatch"
                      );
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/core/interfaces/ISetFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ISetFactory
               * @author Set Protocol
               *
               * The ISetFactory interface provides operability for authorized contracts
               * to interact with SetTokenFactory
               */
              interface ISetFactory {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Return core address
                   *
                   * @return address        core address
                   */
                  function core()
                      external
                      returns (address);
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address[] calldata _components,
                      uint[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              }
              
              // File: contracts/core/tokens/SetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              /**
               * @title SetToken
               * @author Set Protocol
               *
               * Implementation of the basic Set token.
               */
              contract SetToken is
                  ERC20,
                  ERC20Detailed
              {
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  uint256 public naturalUnit;
                  address[] public components;
                  uint256[] public units;
              
                  // Mapping of componentHash to isComponent
                  mapping(address => bool) internal isComponent;
              
                  // Address of the Factory contract that created the SetToken
                  address public factory;
              
                  /* ============ Constructor ============ */
              
                  /**
                   * Constructor function for Set token
                   *
                   * As looping operations are expensive, checking for duplicates will be on the onus of the application developer
                   *
                   * @param _factory          The factory used to create the Set Token
                   * @param _components       A list of component address which you want to include
                   * @param _units            A list of quantities of each component (corresponds to the Set of _components)
                   * @param _naturalUnit      The minimum multiple of Sets that can be issued or redeemed
                   * @param _name             The Set's name
                   * @param _symbol           The Set's symbol
                   */
                  constructor(
                      address _factory,
                      address[] memory _components,
                      uint256[] memory _units,
                      uint256 _naturalUnit,
                      string memory _name,
                      string memory _symbol
                  )
                      public
                      ERC20Detailed(
                          _name,
                          _symbol,
                          18
                      )
                  {
                      // Storing count and unit counts to local variable to save on invocation
                      uint256 unitCount = _units.length;
              
                      // Require naturalUnit passed is greater than 0
                      require(
                          _naturalUnit > 0,
                          "SetToken.constructor: Natural unit must be positive"
                      );
              
                      // Confirm an empty _components array is not passed
                      CommonValidationsLibrary.validateNonEmpty(_components);
              
                      // Confirm there is one quantity for every token address
                      CommonValidationsLibrary.validateEqualLength(_components, _units);
              
                      // NOTE: It will be the onus of developers to check whether the addressExists
                      // are in fact ERC20 addresses
                      uint8 minDecimals = 18;
                      uint8 currentDecimals;
                      for (uint256 i = 0; i < unitCount; i++) {
                          // Check that all units are non-zero
                          uint256 currentUnits = _units[i];
                          require(
                              currentUnits > 0,
                              "SetToken.constructor: Units must be positive"
                          );
              
                          // Check that all addresses are non-zero
                          address currentComponent = _components[i];
                          require(
                              currentComponent != address(0),
                              "SetToken.constructor: Invalid component address"
                          );
              
                          // Figure out which of the components has the minimum decimal value
                          /* solium-disable-next-line security/no-low-level-calls */
                          (bool success, ) = currentComponent.call(abi.encodeWithSignature("decimals()"));
                          if (success) {
                              currentDecimals = ERC20Detailed(currentComponent).decimals();
                              minDecimals = currentDecimals < minDecimals ? currentDecimals : minDecimals;
                          } else {
                              // If one of the components does not implement decimals, we assume the worst
                              // and set minDecimals to 0
                              minDecimals = 0;
                          }
              
                          // Check the component has not already been added
                          require(
                              !tokenIsComponent(currentComponent),
                              "SetToken.constructor: Duplicated component"
                          );
              
                          // Add component to isComponent mapping
                          isComponent[currentComponent] = true;
              
                          // Add component data to components and units state variables
                          components.push(currentComponent);
                          units.push(currentUnits);
                      }
              
                      // This is the minimum natural unit possible for a Set with these components.
                      require(
                          _naturalUnit >= CommonMath.safePower(10, uint256(18).sub(minDecimals)),
                          "SetToken.constructor: Invalid natural unit"
                      );
              
                      factory = _factory;
                      naturalUnit = _naturalUnit;
                  }
              
                  /* ============ Public Functions ============ */
              
                  /*
                   * Mint set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external
                  {
                      // Check that function caller is Core
                      require(
                          msg.sender == ISetFactory(factory).core(),
                          "SetToken.mint: Sender must be core"
                      );
              
                      _mint(_issuer, _quantity);
                  }
              
                  /*
                   * Burn set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external
                  {
                      // Check that function caller is Core
                      require(
                          msg.sender == ISetFactory(factory).core(),
                          "SetToken.burn: Sender must be core"
                      );
              
                      _burn(_from, _quantity);
                  }
              
                  /*
                   * Get addresses of all components in the Set
                   *
                   * @return  componentAddresses       Array of component tokens
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory)
                  {
                      return components;
                  }
              
                  /*
                   * Get units of all tokens in Set
                   *
                   * @return  units       Array of component units
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory)
                  {
                      return units;
                  }
              
                  /*
                   * Validates address is member of Set's components
                   *
                   * @param  _tokenAddress     Address of token being checked
                   * @return  bool             Whether token is member of Set's components
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      public
                      view
                      returns (bool)
                  {
                      return isComponent[_tokenAddress];
                  }
              }

              File 4 of 8: Core
              // File: openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Helps contracts guard against reentrancy attacks.
               * @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]>
               * @dev If you mark a function `nonReentrant`, you should also
               * mark it `external`.
               */
              contract ReentrancyGuard {
                  /// @dev counter to allow mutex lock with only one SSTORE operation
                  uint256 private _guardCounter;
              
                  constructor () internal {
                      // The counter starts at one to prevent changing it from zero to a non-zero
                      // value, which is a more expensive operation.
                      _guardCounter = 1;
                  }
              
                  /**
                   * @dev Prevents a contract from calling itself, directly or indirectly.
                   * Calling a `nonReentrant` function from another `nonReentrant`
                   * function is not supported. It is possible to prevent this from happening
                   * by making the `nonReentrant` function external, and make it call a
                   * `private` function that does the actual work.
                   */
                  modifier nonReentrant() {
                      _guardCounter += 1;
                      uint256 localCounter = _guardCounter;
                      _;
                      require(localCounter == _guardCounter);
                  }
              }
              
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: contracts/lib/CommonValidationsLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              library CommonValidationsLibrary {
              
                  /**
                   * Ensures that an address array is not empty.
                   *
                   * @param  _addressArray       Address array input
                   */
                  function validateNonEmpty(
                      address[] calldata _addressArray
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length > 0,
                          "Address array length must be > 0"
                      );
                  }
              
                  /**
                   * Ensures that an address array and uint256 array are equal length
                   *
                   * @param  _addressArray       Address array input
                   * @param  _uint256Array       Uint256 array input
                   */
                  function validateEqualLength(
                      address[] calldata _addressArray,
                      uint256[] calldata _uint256Array
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length == _uint256Array.length,
                          "Input length mismatch"
                      );
                  }
              }
              
              // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Ownable
               * @dev The Ownable contract has an owner address, and provides basic authorization control
               * functions, this simplifies the implementation of "user permissions".
               */
              contract Ownable {
                  address private _owner;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                   * account.
                   */
                  constructor () internal {
                      _owner = msg.sender;
                      emit OwnershipTransferred(address(0), _owner);
                  }
              
                  /**
                   * @return the address of the owner.
                   */
                  function owner() public view returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(isOwner());
                      _;
                  }
              
                  /**
                   * @return true if `msg.sender` is the owner of the contract.
                   */
                  function isOwner() public view returns (bool) {
                      return msg.sender == _owner;
                  }
              
                  /**
                   * @dev Allows the current owner to relinquish control of the contract.
                   * It will not be possible to call the functions with the `onlyOwner`
                   * modifier anymore.
                   * @notice Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = address(0);
                  }
              
                  /**
                   * @dev Allows the current owner to transfer control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function transferOwnership(address newOwner) public onlyOwner {
                      _transferOwnership(newOwner);
                  }
              
                  /**
                   * @dev Transfers control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function _transferOwnership(address newOwner) internal {
                      require(newOwner != address(0));
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              // File: contracts/core/interfaces/ITransferProxy.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title ITransferProxy
               * @author Set Protocol
               *
               * The ITransferProxy interface provides a light-weight, structured way to interact with the
               * TransferProxy contract from another contract.
               */
              interface ITransferProxy {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Can only be called by authorized core contracts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _quantity       The number of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function transfer(
                      address _token,
                      uint256 _quantity,
                      address _from,
                      address _to
                  )
                      external;
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Can only be called by authorized core contracts.
                   *
                   * @param  _tokens         The addresses of the ERC20 token
                   * @param  _quantities     The numbers of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function batchTransfer(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities,
                      address _from,
                      address _to
                  )
                      external;
              }
              
              // File: contracts/core/interfaces/IVault.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IVault
               * @author Set Protocol
               *
               * The IVault interface provides a light-weight, structured way to interact with the Vault
               * contract from another contract.
               */
              interface IVault {
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer token to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function withdrawTo(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Increment quantity owned of a token for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to attribute to owner
                   */
                  function incrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Decrement quantity owned of a token for a given address. Can only
                   * be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to deattribute to owner
                   */
                  function decrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _token          Address of token being transferred
                   * @param  _from           Address token being transferred from
                   * @param  _to             Address token being transferred to
                   * @param  _quantity       Amount of tokens being transferred
                   */
              
                  function transferBalance(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchWithdrawTo(
                      address[] calldata _tokens,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Increment quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Decrements quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                 /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalance(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Get balance of particular contract for owner.
                   *
                   * @param  _token    The address of the ERC20 token
                   * @param  _owner    The address of the token owner
                   */
                  function getOwnerBalance(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256);
              }
              
              // File: contracts/core/lib/CoreState.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title CoreState
               * @author Set Protocol
               *
               * The CoreState library maintains all state for the Core contract thus
               * allowing it to operate across multiple mixins.
               */
              contract CoreState {
              
                  /* ============ Structs ============ */
              
                  struct State {
                      // Protocol state of operation
                      uint8 operationState;
              
                      // Address of the TransferProxy contract
                      address transferProxy;
              
                      // Address of the Vault contract
                      address vault;
              
                      // Instance of transferProxy contract
                      ITransferProxy transferProxyInstance;
              
                      // Instance of Vault Contract
                      IVault vaultInstance;
              
                      // Mapping of exchange enumeration to address
                      mapping(uint8 => address) exchangeIds;
              
                      // Mapping of approved modules
                      mapping(address => bool) validModules;
              
                      // Mapping of tracked SetToken factories
                      mapping(address => bool) validFactories;
              
                      // Mapping of tracked rebalancing price libraries
                      mapping(address => bool) validPriceLibraries;
              
                      // Mapping of tracked SetTokens
                      mapping(address => bool) validSets;
              
                      // Mapping of tracked disabled SetTokens
                      mapping(address => bool) disabledSets;
              
                      // Array of tracked SetTokens
                      address[] setTokens;
              
                      // Array of tracked modules
                      address[] modules;
              
                      // Array of tracked factories
                      address[] factories;
              
                      // Array of tracked exchange wrappers
                      address[] exchanges;
              
                      // Array of tracked auction price libraries
                      address[] priceLibraries;
                  }
              
                  /* ============ State Variables ============ */
              
                  State public state;
              
                  /* ============ Public Getters ============ */
              
                  /**
                   * Return uint8 representing the operational state of the protocol
                   *
                   * @return uint8           Uint8 representing the operational state of the protocol
                   */
                  function operationState()
                      external
                      view
                      returns (uint8)
                  {
                      return state.operationState;
                  }
              
                  /**
                   * Return address belonging to given exchangeId.
                   *
                   * @param  _exchangeId       ExchangeId number
                   * @return address           Address belonging to given exchangeId
                   */
                  function exchangeIds(
                      uint8 _exchangeId
                  )
                      external
                      view
                      returns (address)
                  {
                      return state.exchangeIds[_exchangeId];
                  }
              
                  /**
                   * Return transferProxy address.
                   *
                   * @return address       transferProxy address
                   */
                  function transferProxy()
                      external
                      view
                      returns (address)
                  {
                      return state.transferProxy;
                  }
              
                  /**
                   * Return vault address
                   *
                   * @return address        vault address
                   */
                  function vault()
                      external
                      view
                      returns (address)
                  {
                      return state.vault;
                  }
              
                  /**
                   * Return boolean indicating if address is valid factory.
                   *
                   * @param  _factory       Factory address
                   * @return bool           Boolean indicating if enabled factory
                   */
                  function validFactories(
                      address _factory
                  )
                      external
                      view
                      returns (bool)
                  {
                      return state.validFactories[_factory];
                  }
              
                  /**
                   * Return boolean indicating if address is valid module.
                   *
                   * @param  _module        Factory address
                   * @return bool           Boolean indicating if enabled factory
                   */
                  function validModules(
                      address _module
                  )
                      external
                      view
                      returns (bool)
                  {
                      return state.validModules[_module];
                  }
              
                  /**
                   * Return boolean indicating if address is valid Set.
                   *
                   * @param  _set           Set address
                   * @return bool           Boolean indicating if valid Set
                   */
                  function validSets(
                      address _set
                  )
                      external
                      view
                      returns (bool)
                  {
                      return state.validSets[_set];
                  }
              
                  /**
                   * Return boolean indicating if address is a disabled Set.
                   *
                   * @param  _set           Set address
                   * @return bool           Boolean indicating if is a disabled Set
                   */
                  function disabledSets(
                      address _set
                  )
                      external
                      view
                      returns (bool)
                  {
                      return state.disabledSets[_set];
                  }
              
                  /**
                   * Return boolean indicating if address is a valid Rebalancing Price Library.
                   *
                   * @param  _priceLibrary    Price library address
                   * @return bool             Boolean indicating if valid Price Library
                   */
                  function validPriceLibraries(
                      address _priceLibrary
                  )
                      external
                      view
                      returns (bool)
                  {
                      return state.validPriceLibraries[_priceLibrary];
                  }
              
                  /**
                   * Return array of all valid Set Tokens.
                   *
                   * @return address[]      Array of valid Set Tokens
                   */
                  function setTokens()
                      external
                      view
                      returns (address[] memory)
                  {
                      return state.setTokens;
                  }
              
                  /**
                   * Return array of all valid Modules.
                   *
                   * @return address[]      Array of valid modules
                   */
                  function modules()
                      external
                      view
                      returns (address[] memory)
                  {
                      return state.modules;
                  }
              
                  /**
                   * Return array of all valid factories.
                   *
                   * @return address[]      Array of valid factories
                   */
                  function factories()
                      external
                      view
                      returns (address[] memory)
                  {
                      return state.factories;
                  }
              
                  /**
                   * Return array of all valid exchange wrappers.
                   *
                   * @return address[]      Array of valid exchange wrappers
                   */
                  function exchanges()
                      external
                      view
                      returns (address[] memory)
                  {
                      return state.exchanges;
                  }
              
                  /**
                   * Return array of all valid price libraries.
                   *
                   * @return address[]      Array of valid price libraries
                   */
                  function priceLibraries()
                      external
                      view
                      returns (address[] memory)
                  {
                      return state.priceLibraries;
                  }
              }
              
              // File: contracts/core/extensions/CoreOperationState.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title CoreOperationState
               * @author Set Protocol
               *
               * The CoreOperationState contract contains methods to alter state of variables that track
               * Core dependency addresses.
               */
              contract CoreOperationState is
                  Ownable,
                  CoreState
              {
              
                  /* ============ Enum ============ */
              
                  /**
                   * Operational:
                   * All Accounting and Issuance related functions are available for usage during this stage
                   *
                   * Shut Down:
                   * Only functions which allow users to redeem and withdraw funds are allowed during this stage
                   */
                  enum OperationState {
                      Operational,
                      ShutDown,
                      InvalidState
                  }
              
                  /* ============ Events ============ */
              
                  event OperationStateChanged(
                      uint8 _prevState,
                      uint8 _newState
                  );
              
                  /* ============ Modifiers ============ */
              
                  modifier whenOperational() {
                      require(
                          state.operationState == uint8(OperationState.Operational),
                          "WhenOperational"
                      );
                      _;
                  }
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Updates the operation state of the protocol.
                   * Can only be called by owner of Core.
                   *
                   * @param  _operationState   Uint8 representing the current protocol operation state
                   */
                  function setOperationState(
                      uint8 _operationState
                  )
                      external
                      onlyOwner
                  {
                      require(
                          _operationState < uint8(OperationState.InvalidState) &&
                          _operationState != state.operationState,
                          "InvalidOperationState"
                      );
              
                      emit OperationStateChanged(
                          state.operationState,
                          _operationState
                      );
              
                      state.operationState = _operationState;
                  }
              }
              
              // File: contracts/core/extensions/CoreAccounting.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              /**
               * @title CoreAccounting
               * @author Set Protocol
               *
               * The CoreAccounting contract interfaces with the vault and transfer proxies for
               * storage of tokenized assets.
               */
              contract CoreAccounting is
                  CoreState,
                  CoreOperationState,
                  ReentrancyGuard
              {
                  // Use SafeMath library for all uint256 arithmetic
                  using SafeMath for uint256;
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Deposit a quantity of tokens to the vault and attribute to sender.
                   *
                   * @param  _token           Address of the token
                   * @param  _quantity        Amount of tokens to deposit
                   */
                  function deposit(
                      address _token,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                      whenOperational
                  {
                      // Don't deposit if quantity <= 0
                      if (_quantity > 0) {
                          // Call TransferProxy contract to transfer user tokens to Vault
                          state.transferProxyInstance.transfer(
                              _token,
                              _quantity,
                              msg.sender,
                              state.vault
                          );
              
                          // Call Vault contract to attribute deposited tokens to user
                          state.vaultInstance.incrementTokenOwner(
                              _token,
                              msg.sender,
                              _quantity
                          );
                      }
                  }
              
                  /**
                   * Withdraw a quantity of tokens from the vault and deattribute from sender.
                   *
                   * @param  _token           Address of the token
                   * @param  _quantity        Amount of tokens to withdraw
                   */
                  function withdraw(
                      address _token,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      // Don't withdraw if quantity <= 0
                      if (_quantity > 0) {
                          // Call Vault contract to deattribute withdrawn tokens from user
                          state.vaultInstance.decrementTokenOwner(
                              _token,
                              msg.sender,
                              _quantity
                          );
              
                          // Call Vault contract to withdraw tokens from Vault to user
                          state.vaultInstance.withdrawTo(
                              _token,
                              msg.sender,
                              _quantity
                          );
                      }
                  }
              
                  /**
                   * Deposit multiple tokens to the vault and attribute to sender.
                   * Quantities should be in the order of the addresses of the tokens being deposited.
                   *
                   * @param  _tokens            Array of the addresses of the tokens
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDeposit(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external
                      nonReentrant
                      whenOperational
                  {
                      // Call internal batch deposit function
                      batchDepositInternal(
                          msg.sender,
                          msg.sender,
                          _tokens,
                          _quantities
                      );
                  }
              
                  /**
                   * Withdraw multiple tokens from the vault and deattribute from sender.
                   * Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _tokens            Array of the addresses of the tokens
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdraw(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external
                      nonReentrant
                  {
                      // Call internal batch withdraw function
                      batchWithdrawInternal(
                          msg.sender,
                          msg.sender,
                          _tokens,
                          _quantities
                      );
                  }
              
                  /**
                   * Transfer tokens associated with the sender's account in vault to another user's
                   * account in vault.
                   *
                   * @param  _token           Address of token being transferred
                   * @param  _to              Address of user receiving tokens
                   * @param  _quantity        Amount of tokens being transferred
                   */
                  function internalTransfer(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                      whenOperational
                  {
                      state.vaultInstance.transferBalance(
                          _token,
                          msg.sender,
                          _to,
                          _quantity
                      );
                  }
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Internal function that deposits multiple tokens to the vault.
                   * Quantities should be in the order of the addresses of the tokens being deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _tokens            Array of the addresses of the tokens being deposited
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDepositInternal(
                      address _from,
                      address _to,
                      address[] memory _tokens,
                      uint256[] memory _quantities
                  )
                      internal
                      whenOperational
                  {
                      // Confirm an empty _tokens or quantity array is not passed
                      CommonValidationsLibrary.validateNonEmpty(_tokens);
              
                      // Confirm there is one quantity for every token address
                      CommonValidationsLibrary.validateEqualLength(_tokens, _quantities);
              
                      state.transferProxyInstance.batchTransfer(
                          _tokens,
                          _quantities,
                          _from,
                          state.vault
                      );
              
                      state.vaultInstance.batchIncrementTokenOwner(
                          _tokens,
                          _to,
                          _quantities
                      );
                  }
              
                  /**
                   * Internal function that withdraws multiple tokens from the vault.
                   * Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _tokens            Array of the addresses of the tokens being withdrawn
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdrawInternal(
                      address _from,
                      address _to,
                      address[] memory _tokens,
                      uint256[] memory _quantities
                  )
                      internal
                  {
                      // Confirm an empty _tokens or quantity array is not passed
                      CommonValidationsLibrary.validateNonEmpty(_tokens);
              
                      // Confirm there is one quantity for every token address
                      CommonValidationsLibrary.validateEqualLength(_tokens, _quantities);
              
                      // Call Vault contract to deattribute withdrawn tokens from user
                      state.vaultInstance.batchDecrementTokenOwner(
                          _tokens,
                          _from,
                          _quantities
                      );
              
                      // Call Vault contract to withdraw tokens from Vault to user
                      state.vaultInstance.batchWithdrawTo(
                          _tokens,
                          _to,
                          _quantities
                      );
                  }
              }
              
              // File: contracts/lib/AddressArrayUtils.sol
              
              // Pulled in from Cryptofin Solidity package in order to control Solidity compiler version
              // https://github.com/cryptofinlabs/cryptofin-solidity/blob/master/contracts/array-utils/AddressArrayUtils.sol
              
              pragma solidity 0.5.7;
              
              
              library AddressArrayUtils {
              
                  /**
                   * Finds the index of the first occurrence of the given element.
                   * @param A The input array to search
                   * @param a The value to find
                   * @return Returns (index and isIn) for the first occurrence starting from index 0
                   */
                  function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length; i++) {
                          if (A[i] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                  * Returns true if the value is present in the list. Uses indexOf internally.
                  * @param A The input array to search
                  * @param a The value to find
                  * @return Returns isIn for the first occurrence starting from index 0
                  */
                  function contains(address[] memory A, address a) internal pure returns (bool) {
                      bool isIn;
                      (, isIn) = indexOf(A, a);
                      return isIn;
                  }
              
                  /// @return Returns index and isIn for the first occurrence starting from
                  /// end
                  function indexOfFromEnd(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = length; i > 0; i--) {
                          if (A[i - 1] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                   * Returns the combination of the two arrays
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A extended by B
                   */
                  function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 aLength = A.length;
                      uint256 bLength = B.length;
                      address[] memory newAddresses = new address[](aLength + bLength);
                      for (uint256 i = 0; i < aLength; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = 0; j < bLength; j++) {
                          newAddresses[aLength + j] = B[j];
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the array with a appended to A.
                   * @param A The first array
                   * @param a The value to append
                   * @return Returns A appended by a
                   */
                  function append(address[] memory A, address a) internal pure returns (address[] memory) {
                      address[] memory newAddresses = new address[](A.length + 1);
                      for (uint256 i = 0; i < A.length; i++) {
                          newAddresses[i] = A[i];
                      }
                      newAddresses[A.length] = a;
                      return newAddresses;
                  }
              
                  /**
                   * Returns the combination of two storage arrays.
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A appended by a
                   */
                  function sExtend(address[] storage A, address[] storage B) internal {
                      uint256 length = B.length;
                      for (uint256 i = 0; i < length; i++) {
                          A.push(B[i]);
                      }
                  }
              
                  /**
                   * Returns the intersection of two arrays. Arrays are treated as collections, so duplicates are kept.
                   * @param A The first array
                   * @param B The second array
                   * @return The intersection of the two arrays
                   */
                  function intersect(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 newLength = 0;
                      for (uint256 i = 0; i < length; i++) {
                          if (contains(B, A[i])) {
                              includeMap[i] = true;
                              newLength++;
                          }
                      }
                      address[] memory newAddresses = new address[](newLength);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the union of the two arrays. Order is not guaranteed.
                   * @param A The first array
                   * @param B The second array
                   * @return The union of the two arrays
                   */
                  function union(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      address[] memory leftDifference = difference(A, B);
                      address[] memory rightDifference = difference(B, A);
                      address[] memory intersection = intersect(A, B);
                      return extend(leftDifference, extend(intersection, rightDifference));
                  }
              
                  /**
                   * Alternate implementation
                   * Assumes there are no duplicates
                   */
                  function unionB(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      bool[] memory includeMap = new bool[](A.length + B.length);
                      uint256 count = 0;
                      for (uint256 i = 0; i < A.length; i++) {
                          includeMap[i] = true;
                          count++;
                      }
                      for (uint256 j = 0; j < B.length; j++) {
                          if (!contains(A, B[j])) {
                              includeMap[A.length + j] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 k = 0;
                      for (uint256 m = 0; m < A.length; m++) {
                          if (includeMap[m]) {
                              newAddresses[k] = A[m];
                              k++;
                          }
                      }
                      for (uint256 n = 0; n < B.length; n++) {
                          if (includeMap[A.length + n]) {
                              newAddresses[k] = B[n];
                              k++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Computes the difference of two arrays. Assumes there are no duplicates.
                   * @param A The first array
                   * @param B The second array
                   * @return The difference of the two arrays
                   */
                  function difference(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 count = 0;
                      // First count the new length because can't push for in-memory arrays
                      for (uint256 i = 0; i < length; i++) {
                          address e = A[i];
                          if (!contains(B, e)) {
                              includeMap[i] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                  * @dev Reverses storage array in place
                  */
                  function sReverse(address[] storage A) internal {
                      address t;
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length / 2; i++) {
                          t = A[i];
                          A[i] = A[A.length - i - 1];
                          A[A.length - i - 1] = t;
                      }
                  }
              
                  /**
                  * Removes specified index from array
                  * Resulting ordering is not guaranteed
                  * @return Returns the new array and the removed entry
                  */
                  function pop(address[] memory A, uint256 index)
                      internal
                      pure
                      returns (address[] memory, address)
                  {
                      uint256 length = A.length;
                      address[] memory newAddresses = new address[](length - 1);
                      for (uint256 i = 0; i < index; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = index + 1; j < length; j++) {
                          newAddresses[j - 1] = A[j];
                      }
                      return (newAddresses, A[index]);
                  }
              
                  /**
                   * @return Returns the new array
                   */
                  function remove(address[] memory A, address a)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert();
                      } else {
                          (address[] memory _A,) = pop(A, index);
                          return _A;
                      }
                  }
              
                  function sPop(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      for (uint256 i = index; i < length - 1; i++) {
                          A[i] = A[i + 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                  * Deletes address at index and fills the spot with the last address.
                  * Order is not preserved.
                  * @return Returns the removed entry
                  */
                  function sPopCheap(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      if (index != length - 1) {
                          A[index] = A[length - 1];
                          delete A[length - 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                   * Deletes address at index. Works by swapping it with the last address, then deleting.
                   * Order is not preserved
                   * @param A Storage array to remove from
                   */
                  function sRemoveCheap(address[] storage A, address a) internal {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert("Error: entry not found");
                      } else {
                          sPopCheap(A, index);
                          return;
                      }
                  }
              
                  /**
                   * Returns whether or not there's a duplicate. Runs in O(n^2).
                   * @param A Array to search
                   * @return Returns true if duplicate, false otherwise
                   */
                  function hasDuplicate(address[] memory A) internal pure returns (bool) {
                      if (A.length == 0) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length - 1; i++) {
                          for (uint256 j = i + 1; j < A.length; j++) {
                              if (A[i] == A[j]) {
                                  return true;
                              }
                          }
                      }
                      return false;
                  }
              
                  /**
                   * Returns whether the two arrays are equal.
                   * @param A The first array
                   * @param B The second array
                   * @return True is the arrays are equal, false if not.
                   */
                  function isEqual(address[] memory A, address[] memory B) internal pure returns (bool) {
                      if (A.length != B.length) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length; i++) {
                          if (A[i] != B[i]) {
                              return false;
                          }
                      }
                      return true;
                  }
              
                  /**
                   * Returns the elements indexed at indexArray.
                   * @param A The array to index
                   * @param indexArray The array to use to index
                   * @return Returns array containing elements indexed at indexArray
                   */
                  function argGet(address[] memory A, uint256[] memory indexArray)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      address[] memory array = new address[](indexArray.length);
                      for (uint256 i = 0; i < indexArray.length; i++) {
                          array[i] = A[indexArray[i]];
                      }
                      return array;
                  }
              
              }
              
              // File: contracts/lib/TimeLockUpgrade.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title TimeLockUpgrade
               * @author Set Protocol
               *
               * The TimeLockUpgrade contract contains a modifier for handling minimum time period updates
               */
              contract TimeLockUpgrade is
                  Ownable
              {
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  // Timelock Upgrade Period in seconds
                  uint256 public timeLockPeriod;
              
                  // Mapping of upgradable units and initialized timelock
                  mapping(bytes32 => uint256) public timeLockedUpgrades;
              
                  /* ============ Events ============ */
              
                  event UpgradeRegistered(
                      bytes32 _upgradeHash,
                      uint256 _timestamp
                  );
              
                  /* ============ Modifiers ============ */
              
                  modifier timeLockUpgrade() {
                      // If the time lock period is 0, then allow non-timebound upgrades.
                      // This is useful for initialization of the protocol and for testing.
                      if (timeLockPeriod == 0) {
                          _;
              
                          return;
                      }
              
                      // The upgrade hash is defined by the hash of the transaction call data,
                      // which uniquely identifies the function as well as the passed in arguments.
                      bytes32 upgradeHash = keccak256(
                          abi.encodePacked(
                              msg.data
                          )
                      );
              
                      uint256 registrationTime = timeLockedUpgrades[upgradeHash];
              
                      // If the upgrade hasn't been registered, register with the current time.
                      if (registrationTime == 0) {
                          timeLockedUpgrades[upgradeHash] = block.timestamp;
              
                          emit UpgradeRegistered(
                              upgradeHash,
                              block.timestamp
                          );
              
                          return;
                      }
              
                      require(
                          block.timestamp >= registrationTime.add(timeLockPeriod),
                          "TimeLockUpgrade: Time lock period must have elapsed."
                      );
              
                      // Reset the timestamp to 0
                      timeLockedUpgrades[upgradeHash] = 0;
              
                      // Run the rest of the upgrades
                      _;
                  }
              
                  /* ============ Function ============ */
              
                  /**
                   * Change timeLockPeriod period. Generally called after initially settings have been set up.
                   *
                   * @param  _timeLockPeriod   Time in seconds that upgrades need to be evaluated before execution
                   */
                  function setTimeLockPeriod(
                      uint256 _timeLockPeriod
                  )
                      external
                      onlyOwner
                  {
                      // Only allow setting of the timeLockPeriod if the period is greater than the existing
                      require(
                          _timeLockPeriod > timeLockPeriod,
                          "TimeLockUpgrade: New period must be greater than existing"
                      );
              
                      timeLockPeriod = _timeLockPeriod;
                  }
              }
              
              // File: contracts/core/extensions/CoreAdmin.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              /**
               * @title CoreAdmin
               * @author Set Protocol
               *
               * The CoreAdmin contract contains methods to alter state of variables that track
               * Core dependency addresses.
               */
              contract CoreAdmin is
                  Ownable,
                  CoreState,
                  TimeLockUpgrade
              {
                  using AddressArrayUtils for address[];
              
                  /* ============ Events ============ */
              
                  event FactoryAdded(
                      address _factory
                  );
              
                  event FactoryRemoved(
                      address _factory
                  );
              
                  event ExchangeAdded(
                      uint8 _exchangeId,
                      address _exchange
                  );
              
                  event ExchangeRemoved(
                      uint8 _exchangeId
                  );
              
                  event ModuleAdded(
                      address _module
                  );
              
                  event ModuleRemoved(
                      address _module
                  );
              
                  event SetDisabled(
                      address _set
                  );
              
                  event SetReenabled(
                      address _set
                  );
              
                  event PriceLibraryAdded(
                      address _priceLibrary
                  );
              
                  event PriceLibraryRemoved(
                      address _priceLibrary
                  );
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Add a factory from the mapping of tracked factories.
                   * Can only be called by owner of Core.
                   *
                   * @param  _factory   Address of the factory conforming to ISetFactory
                   */
                  function addFactory(
                      address _factory
                  )
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      require(
                          !state.validFactories[_factory]
                      );
              
                      state.validFactories[_factory] = true;
              
                      state.factories = state.factories.append(_factory);
              
                      emit FactoryAdded(
                          _factory
                      );
                  }
              
                  /**
                   * Remove a factory from the mapping of tracked factories.
                   * Can only be called by owner of Core.
                   *
                   * @param  _factory   Address of the factory conforming to ISetFactory
                   */
                  function removeFactory(
                      address _factory
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.validFactories[_factory]
                      );
              
                      state.factories = state.factories.remove(_factory);
              
                      state.validFactories[_factory] = false;
              
                      emit FactoryRemoved(
                          _factory
                      );
                  }
              
                  /**
                   * Add an exchange address with the mapping of tracked exchanges.
                   * Can only be called by owner of Core.
                   *
                   * @param _exchangeId   Enumeration of exchange within the mapping
                   * @param _exchange     Address of the exchange conforming to IExchangeWrapper
                   */
                  function addExchange(
                      uint8 _exchangeId,
                      address _exchange
                  )
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      require(
                          state.exchangeIds[_exchangeId] == address(0)
                      );
              
                      state.exchangeIds[_exchangeId] = _exchange;
              
                      state.exchanges = state.exchanges.append(_exchange);
              
                      emit ExchangeAdded(
                          _exchangeId,
                          _exchange
                      );
                  }
              
                  /**
                   * Remove an exchange address with the mapping of tracked exchanges.
                   * Can only be called by owner of Core.
                   *
                   * @param _exchangeId   Enumeration of exchange within the mapping
                   * @param _exchange     Address of the exchange conforming to IExchangeWrapper
                   */
                  function removeExchange(
                      uint8 _exchangeId,
                      address _exchange
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.exchangeIds[_exchangeId] != address(0) &&
                          state.exchangeIds[_exchangeId] == _exchange
                      );
              
                      state.exchanges = state.exchanges.remove(_exchange);
              
                      state.exchangeIds[_exchangeId] = address(0);
              
                      emit ExchangeRemoved(
                          _exchangeId
                      );
                  }
              
                  /**
                   * Add a module address with the mapping of tracked modules.
                   * Can only be called by owner of Core.
                   *
                   * @param _module     Address of the module
                   */
                  function addModule(
                      address _module
                  )
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      require(
                          !state.validModules[_module]
                      );
              
                      state.validModules[_module] = true;
              
                      state.modules = state.modules.append(_module);
              
                      emit ModuleAdded(
                          _module
                      );
                  }
              
                  /**
                   * Remove a module address with the mapping of tracked modules.
                   * Can only be called by owner of Core.
                   *
                   * @param _module   Enumeration of module within the mapping
                   */
                  function removeModule(
                      address _module
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.validModules[_module]
                      );
              
                      state.modules = state.modules.remove(_module);
              
                      state.validModules[_module] = false;
              
                      emit ModuleRemoved(
                          _module
                      );
                  }
              
                  /**
                   * Disables a Set from the mapping and array of tracked Sets.
                   * Can only be called by owner of Core.
                   *
                   * @param  _set       Address of the Set
                   */
                  function disableSet(
                      address _set
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.validSets[_set]
                      );
              
                      state.setTokens = state.setTokens.remove(_set);
              
                      state.validSets[_set] = false;
              
                      state.disabledSets[_set] = true;
              
                      emit SetDisabled(
                          _set
                      );
                  }
              
                  /**
                   * Enables a Set from the mapping and array of tracked Sets if it has been previously disabled
                   * Can only be called by owner of Core.
                   *
                   * @param  _set       Address of the Set
                   */
                  function reenableSet(
                      address _set
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.disabledSets[_set]
                      );
              
                      state.setTokens = state.setTokens.append(_set);
              
                      state.validSets[_set] = true;
              
                      state.disabledSets[_set] = false;
              
                      emit SetReenabled(
                          _set
                      );
                  }
              
                  /**
                   * Add a price library from the mapping of tracked price libraries.
                   * Can only be called by owner of Core.
                   *
                   * @param  _priceLibrary   Address of the price library
                   */
                  function addPriceLibrary(
                      address _priceLibrary
                  )
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      require(
                          !state.validPriceLibraries[_priceLibrary]
                      );
              
                      state.validPriceLibraries[_priceLibrary] = true;
              
                      state.priceLibraries = state.priceLibraries.append(_priceLibrary);
              
                      emit PriceLibraryAdded(
                          _priceLibrary
                      );
                  }
              
                  /**
                   * Remove a price library from the mapping of tracked price libraries.
                   * Can only be called by owner of Core.
                   *
                   * @param  _priceLibrary   Address of the price library
                   */
                  function removePriceLibrary(
                      address _priceLibrary
                  )
                      external
                      onlyOwner
                  {
                      require(
                          state.validPriceLibraries[_priceLibrary]
                      );
              
                      state.priceLibraries = state.priceLibraries.remove(_priceLibrary);
              
                      state.validPriceLibraries[_priceLibrary] = false;
              
                      emit PriceLibraryRemoved(
                          _priceLibrary
                      );
                  }
              }
              
              // File: contracts/core/interfaces/ISetFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ISetFactory
               * @author Set Protocol
               *
               * The ISetFactory interface provides operability for authorized contracts
               * to interact with SetTokenFactory
               */
              interface ISetFactory {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Return core address
                   *
                   * @return address        core address
                   */
                  function core()
                      external
                      returns (address);
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address[] calldata _components,
                      uint[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              }
              
              // File: contracts/core/extensions/CoreFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title CoreFactory
               * @author Set Protocol
               *
               * The CoreFactory contract contains Set Token creation operations
               */
              contract CoreFactory is
                  CoreState
              {
                  /* ============ Events ============ */
              
                  event SetTokenCreated(
                      address indexed _setTokenAddress,
                      address _factory,
                      address[] _components,
                      uint256[] _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol
                  );
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _factory              The address of the Factory to create from
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address _factory,
                      address[] calldata _components,
                      uint256[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address)
                  {
                      // Verify Factory is linked to Core
                      require(
                          state.validFactories[_factory],
                          "CreateSet"
                      );
              
                      // Create the Set
                      address newSetTokenAddress = ISetFactory(_factory).createSet(
                          _components,
                          _units,
                          _naturalUnit,
                          _name,
                          _symbol,
                          _callData
                      );
              
                      // Add Set to the mapping of tracked Sets
                      state.validSets[newSetTokenAddress] = true;
              
                      // Add Set to the array of tracked Sets
                      state.setTokens.push(newSetTokenAddress);
              
                      // Emit Set Token creation log
                      emit SetTokenCreated(
                          newSetTokenAddress,
                          _factory,
                          _components,
                          _units,
                          _naturalUnit,
                          _name,
                          _symbol
                      );
              
                      return newSetTokenAddress;
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/core/lib/CoreIssuanceLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              /**
               * @title CoreIssuanceLibrary
               * @author Set Protocol
               *
               * This library contains functions for calculating deposit, withdrawal,and transfer quantities
               */
              library CoreIssuanceLibrary {
              
                  using SafeMath for uint256;
              
                  /**
                   * Calculate the quantities required to deposit and decrement during issuance. Takes into account
                   * the tokens an owner already has in the vault.
                   *
                   * @param _components                           Addresses of components
                   * @param _componentQuantities                  Component quantities to increment and withdraw
                   * @param _owner                                Address to deposit and decrement quantities from
                   * @param _vault                                Address to vault
                   * @return uint256[] decrementQuantities        Quantities to decrement from vault
                   * @return uint256[] depositQuantities          Quantities to deposit into the vault
                   */
                  function calculateDepositAndDecrementQuantities(
                      address[] calldata _components,
                      uint256[] calldata _componentQuantities,
                      address _owner,
                      address _vault
                  )
                      external
                      view
                      returns (
                          uint256[] memory /* decrementQuantities */,
                          uint256[] memory /* depositQuantities */
                      )
                  {
                      uint256 componentCount = _components.length;
                      uint256[] memory decrementTokenOwnerValues = new uint256[](componentCount);
                      uint256[] memory depositQuantities = new uint256[](componentCount);
              
                      for (uint256 i = 0; i < componentCount; i++) {
                          // Fetch component quantity in vault
                          uint256 vaultBalance = IVault(_vault).getOwnerBalance(
                              _components[i],
                              _owner
                          );
              
                          // If the vault holds enough components, decrement the full amount
                          if (vaultBalance >= _componentQuantities[i]) {
                              decrementTokenOwnerValues[i] = _componentQuantities[i];
                          } else {
                              // User has less than required amount, decrement the vault by full balance
                              if (vaultBalance > 0) {
                                  decrementTokenOwnerValues[i] = vaultBalance;
                              }
              
                              depositQuantities[i] = _componentQuantities[i].sub(vaultBalance);
                          }
                      }
              
                      return (
                          decrementTokenOwnerValues,
                          depositQuantities
                      );
                  }
              
                  /**
                   * Calculate the quantities required to withdraw and increment during redeem and withdraw. Takes into
                   * account a bitmask exclusion parameter.
                   *
                   * @param _componentQuantities                  Component quantities to increment and withdraw
                   * @param _toExclude                            Mask of indexes of tokens to exclude from withdrawing
                   * @return uint256[] incrementQuantities        Quantities to increment in vault
                   * @return uint256[] withdrawQuantities         Quantities to withdraw from vault
                   */
                  function calculateWithdrawAndIncrementQuantities(
                      uint256[] calldata _componentQuantities,
                      uint256 _toExclude
                  )
                      external
                      pure
                      returns (
                          uint256[] memory /* incrementQuantities */,
                          uint256[] memory /* withdrawQuantities */
                      )
                  {
                      uint256 componentCount = _componentQuantities.length;
                      uint256[] memory incrementTokenOwnerValues = new uint256[](componentCount);
                      uint256[] memory withdrawToValues = new uint256[](componentCount);
              
                      // Loop through and decrement vault balances for the set, withdrawing if requested
                      for (uint256 i = 0; i < componentCount; i++) {
                          // Calculate bit index of current component
                          uint256 componentBitIndex = CommonMath.safePower(2, i);
              
                          // Transfer to user unless component index is included in _toExclude
                          if ((_toExclude & componentBitIndex) != 0) {
                              incrementTokenOwnerValues[i] = _componentQuantities[i];
                          } else {
                              withdrawToValues[i] = _componentQuantities[i];
                          }
                      }
              
                      return (
                          incrementTokenOwnerValues,
                          withdrawToValues
                      );
                  }
              
                  /**
                   * Calculate the required component quantities required for issuance or rdemption for a given
                   * quantity of Set Tokens
                   *
                   * @param _componentUnits   The units of the component token
                   * @param _naturalUnit      The natural unit of the Set token
                   * @param _quantity         The number of tokens being redeem
                   * @return uint256[]        Required quantities in base units of components
                   */
                  function calculateRequiredComponentQuantities(
                      uint256[] calldata _componentUnits,
                      uint256 _naturalUnit,
                      uint256 _quantity
                  )
                      external
                      pure
                      returns (uint256[] memory)
                  {
                      require(
                          _quantity.mod(_naturalUnit) == 0,
                          "CoreIssuanceLibrary: Quantity must be a multiple of nat unit"
                      );
              
                      uint256[] memory tokenValues = new uint256[](_componentUnits.length);
              
                      // Transfer the underlying tokens to the corresponding token balances
                      for (uint256 i = 0; i < _componentUnits.length; i++) {
                          tokenValues[i] = _quantity.div(_naturalUnit).mul(_componentUnits[i]);
                      }
              
                      return tokenValues;
                  }
              
              }
              
              // File: contracts/core/interfaces/ISetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title ISetToken
               * @author Set Protocol
               *
               * The ISetToken interface provides a light-weight, structured way to interact with the
               * SetToken contract from another contract.
               */
              interface ISetToken {
              
                  /* ============ External Functions ============ */
              
                  /*
                   * Get natural unit of Set
                   *
                   * @return  uint256       Natural unit of Set
                   */
                  function naturalUnit()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get addresses of all components in the Set
                   *
                   * @return  componentAddresses       Array of component tokens
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get units of all tokens in Set
                   *
                   * @return  units       Array of component units
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Checks to make sure token is component of Set
                   *
                   * @param  _tokenAddress     Address of token being checked
                   * @return  bool             True if token is component of Set
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      external
                      view
                      returns (bool);
              
                  /*
                   * Mint set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Burn set token for given address
                   * Can only be called by authorized contracts
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                  * Transfer token for a specified address
                  *
                  * @param to The address to transfer to.
                  * @param value The amount to be transferred.
                  */
                  function transfer(
                      address to,
                      uint256 value
                  )
                      external;
              }
              
              // File: contracts/core/lib/SetTokenLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              library SetTokenLibrary {
                  using SafeMath for uint256;
              
                  struct SetDetails {
                      uint256 naturalUnit;
                      address[] components;
                      uint256[] units;
                  }
              
                  /**
                   * Validates that passed in tokens are all components of the Set
                   *
                   * @param _set                      Address of the Set
                   * @param _tokens                   List of tokens to check
                   */
                  function validateTokensAreComponents(
                      address _set,
                      address[] calldata _tokens
                  )
                      external
                      view
                  {
                      for (uint256 i = 0; i < _tokens.length; i++) {
                          // Make sure all tokens are members of the Set
                          require(
                              ISetToken(_set).tokenIsComponent(_tokens[i]),
                              "SetTokenLibrary.validateTokensAreComponents: Component must be a member of Set"
                          );
              
                      }
                  }
              
                  /**
                   * Validates that passed in quantity is a multiple of the natural unit of the Set.
                   *
                   * @param _set                      Address of the Set
                   * @param _quantity                   Quantity to validate
                   */
                  function isMultipleOfSetNaturalUnit(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      view
                  {
                      require(
                          _quantity.mod(ISetToken(_set).naturalUnit()) == 0,
                          "SetTokenLibrary.isMultipleOfSetNaturalUnit: Quantity is not a multiple of nat unit"
                      );
                  }
              
                  /**
                   * Retrieves the Set's natural unit, components, and units.
                   *
                   * @param _set                      Address of the Set
                   * @return SetDetails               Struct containing the natural unit, components, and units
                   */
                  function getSetDetails(
                      address _set
                  )
                      internal
                      view
                      returns (SetDetails memory)
                  {
                      // Declare interface variables
                      ISetToken setToken = ISetToken(_set);
              
                      // Fetch set token properties
                      uint256 naturalUnit = setToken.naturalUnit();
                      address[] memory components = setToken.getComponents();
                      uint256[] memory units = setToken.getUnits();
              
                      return SetDetails({
                          naturalUnit: naturalUnit,
                          components: components,
                          units: units
                      });
                  }
              }
              
              // File: contracts/core/extensions/CoreIssuance.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              /**
               * @title CoreIssuance
               * @author Set Protocol
               *
               * The CoreIssuance contract contains function related to issuing and redeeming Sets.
               */
              contract CoreIssuance is
                  CoreState,
                  CoreOperationState,
                  ReentrancyGuard
              {
                  // Use SafeMath library for all uint256 arithmetic
                  using SafeMath for uint256;
              
                  /* ============ Events ============ */
              
                  event SetIssued(
                      address _setAddress,
                      uint256 _quantity
                  );
              
                  event SetRedeemed(
                      address _setAddress,
                      uint256 _quantity
                  );
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Issues a specified Set for a specified quantity to the caller
                   * using the caller's components from the wallet and vault.
                   *
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issue(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      issueInternal(
                          msg.sender,
                          msg.sender,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Converts user's components into Set Tokens owned by the user and stored in Vault
                   *
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function issueInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      issueInVaultInternal(
                          msg.sender,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Issues a specified Set for a specified quantity to the recipient
                   * using the caller's components from the wallet and vault.
                   *
                   * @param  _recipient    Address to issue to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      issueInternal(
                          msg.sender,
                          _recipient,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Exchange Set tokens for underlying components to the user held in the Vault.
                   *
                   * @param  _set          Address of the Set to redeem
                   * @param  _quantity     Number of tokens to redeem
                   */
                  function redeem(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      redeemInternal(
                          msg.sender,
                          msg.sender,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Composite method to redeem and withdraw with a single transaction
                   *
                   * Normally, you should expect to be able to withdraw all of the tokens.
                   * However, some have central abilities to freeze transfers (e.g. EOS). _toExclude
                   * allows you to optionally specify which component tokens to exclude when
                   * redeeming. They will remain in the vault under the users' addresses.
                   *
                   * @param _set          Address of the Set
                   * @param _to           Address to withdraw or attribute tokens to
                   * @param _quantity     Number of tokens to redeem
                   * @param _toExclude    Mask of indexes of tokens to exclude from withdrawing
                   */
                  function redeemAndWithdrawTo(
                      address _set,
                      address _to,
                      uint256 _quantity,
                      uint256 _toExclude
                  )
                      external
                      nonReentrant
                  {
                      uint256[] memory componentTransferValues = redeemAndDecrementVault(
                          _set,
                          msg.sender,
                          _quantity
                      );
              
                      // Calculate the withdraw and increment quantities to specified address
                      uint256[] memory incrementTokenOwnerValues;
                      uint256[] memory withdrawToValues;
                      (
                          incrementTokenOwnerValues,
                          withdrawToValues
                      ) = CoreIssuanceLibrary.calculateWithdrawAndIncrementQuantities(
                          componentTransferValues,
                          _toExclude
                      );
              
                      address[] memory components = ISetToken(_set).getComponents();
              
                      // Increment excluded components to the specified address
                      state.vaultInstance.batchIncrementTokenOwner(
                          components,
                          _to,
                          incrementTokenOwnerValues
                      );
              
                      // Withdraw non-excluded components and attribute to specified address
                      state.vaultInstance.batchWithdrawTo(
                          components,
                          _to,
                          withdrawToValues
                      );
                  }
              
                  /**
                   * Convert the caller's Set tokens held in the vault into underlying components to the user
                   * held in the Vault.
                   *
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function redeemInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      // Decrement ownership of Set token in the vault
                      state.vaultInstance.decrementTokenOwner(
                          _set,
                          msg.sender,
                          _quantity
                      );
              
                      redeemInternal(
                          state.vault,
                          msg.sender,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Redeem Set token and return components to specified recipient. The components
                   * are left in the vault after redemption in the recipient's name.
                   *
                   * @param _recipient    Recipient of Set being issued
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function redeemTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external
                      nonReentrant
                  {
                      redeemInternal(
                          msg.sender,
                          _recipient,
                          _set,
                          _quantity
                      );
                  }
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Exchange components for Set tokens, accepting any owner
                   * Used in issue, issueTo, and issueInVaultInternal
                   *
                   * @param  _componentOwner  Address to use tokens from
                   * @param  _setRecipient    Address to issue Set to
                   * @param  _set             Address of the Set to issue
                   * @param  _quantity        Number of tokens to issue
                   */
                  function issueInternal(
                      address _componentOwner,
                      address _setRecipient,
                      address _set,
                      uint256 _quantity
                  )
                      internal
                      whenOperational
                  {
                      // Verify Set was created by Core and is enabled
                      require(
                          state.validSets[_set],
                          "IssueInternal"
                      );
              
                      // Validate quantity is multiple of natural unit
                      SetTokenLibrary.isMultipleOfSetNaturalUnit(_set, _quantity);
              
                      SetTokenLibrary.SetDetails memory setToken = SetTokenLibrary.getSetDetails(_set);
              
                      // Calculate component quantities required to issue
                      uint256[] memory requiredComponentQuantities = CoreIssuanceLibrary.calculateRequiredComponentQuantities(
                          setToken.units,
                          setToken.naturalUnit,
                          _quantity
                      );
              
                      // Calculate the withdraw and increment quantities to caller
                      uint256[] memory decrementTokenOwnerValues;
                      uint256[] memory depositValues;
                      (
                          decrementTokenOwnerValues,
                          depositValues
                      ) = CoreIssuanceLibrary.calculateDepositAndDecrementQuantities(
                          setToken.components,
                          requiredComponentQuantities,
                          _componentOwner,
                          state.vault
                      );
              
                      // Decrement components used for issuance in vault
                      state.vaultInstance.batchDecrementTokenOwner(
                          setToken.components,
                          _componentOwner,
                          decrementTokenOwnerValues
                      );
              
                      // Deposit tokens used for issuance into vault
                      state.transferProxyInstance.batchTransfer(
                          setToken.components,
                          depositValues,
                          _componentOwner,
                          state.vault
                      );
              
                      // Increment the vault balance of the set token for the components
                      state.vaultInstance.batchIncrementTokenOwner(
                          setToken.components,
                          _set,
                          requiredComponentQuantities
                      );
              
                      // Issue set token
                      ISetToken(_set).mint(
                          _setRecipient,
                          _quantity
                      );
              
                      emit SetIssued(
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Converts recipient's components into Set Tokens held directly in Vault.
                   * Used in issueInVault
                   *
                   * @param _recipient    Address to issue to
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to issue
                   */
                  function issueInVaultInternal(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      internal
                  {
                      issueInternal(
                          _recipient,
                          state.vault,
                          _set,
                          _quantity
                      );
              
                      // Increment ownership of Set token in the vault
                      state.vaultInstance.incrementTokenOwner(
                          _set,
                          _recipient,
                          _quantity
                      );
                  }
              
                  /**
                   * Exchange Set tokens for underlying components. Components are attributed in the vault.
                   * Used in redeem, redeemInVault, and redeemTo
                   *
                   * @param _burnAddress       Address to burn tokens from
                   * @param _incrementAddress  Address to increment component tokens to
                   * @param _set               Address of the Set to redeem
                   * @param _quantity          Number of tokens to redeem
                   */
                  function redeemInternal(
                      address _burnAddress,
                      address _incrementAddress,
                      address _set,
                      uint256 _quantity
                  )
                      internal
                  {
                      uint256[] memory componentQuantities = redeemAndDecrementVault(
                          _set,
                          _burnAddress,
                          _quantity
                      );
              
                      // Increment the component amount
                      address[] memory components = ISetToken(_set).getComponents();
                      state.vaultInstance.batchIncrementTokenOwner(
                          components,
                          _incrementAddress,
                          componentQuantities
                      );
                  }
              
                 /**
                   * Private method that validates inputs, redeems Set, and decrements
                   * the components in the vault
                   *
                   * @param _set                  Address of the Set to redeem
                   * @param _burnAddress          Address to burn tokens from
                   * @param _quantity             Number of tokens to redeem
                   * @return componentQuantities  Transfer value of components
                   */
                  function redeemAndDecrementVault(
                      address _set,
                      address _burnAddress,
                      uint256 _quantity
                  )
                      private
                      returns (uint256[] memory)
                  {
                      // Verify Set was created by Core and is enabled
                      require(
                          state.validSets[_set],
                          "RedeemAndDecrementVault"
                      );
              
                      // Validate quantity is multiple of natural unit
                      SetTokenLibrary.isMultipleOfSetNaturalUnit(_set, _quantity);
              
                      // Burn the Set token (thereby decrementing the Set balance)
                      ISetToken(_set).burn(
                          _burnAddress,
                          _quantity
                      );
              
                      SetTokenLibrary.SetDetails memory setToken = SetTokenLibrary.getSetDetails(_set);
              
                      // Calculate component quantities to redeem
                      uint256[] memory componentQuantities = CoreIssuanceLibrary.calculateRequiredComponentQuantities(
                          setToken.units,
                          setToken.naturalUnit,
                          _quantity
                      );
              
                      // Decrement components from Set's possession
                      state.vaultInstance.batchDecrementTokenOwner(
                          setToken.components,
                          _set,
                          componentQuantities
                      );
              
                      emit SetRedeemed(
                          _set,
                          _quantity
                      );
              
                      return componentQuantities;
                  }
              }
              
              // File: contracts/core/interfaces/ICoreAccounting.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ICoreAccounting
               * @author Set Protocol
               *
               * The ICoreAccounting Contract defines all the functions exposed in the CoreIssuance
               * extension.
               */
              contract ICoreAccounting {
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Internal function that deposits multiple tokens to the vault.
                   * Quantities should be in the order of the addresses of the tokens being deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _tokens            Array of the addresses of the tokens being deposited
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDepositInternal(
                      address _from,
                      address _to,
                      address[] memory _tokens,
                      uint[] memory _quantities
                  )
                      internal;
              
                  /**
                   * Internal function that withdraws multiple tokens from the vault.
                   * Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _tokens            Array of the addresses of the tokens being withdrawn
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdrawInternal(
                      address _from,
                      address _to,
                      address[] memory _tokens,
                      uint256[] memory _quantities
                  )
                      internal;
              }
              
              // File: contracts/core/interfaces/ICoreIssuance.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ICoreIssuance
               * @author Set Protocol
               *
               * The ICoreIssuance Contract defines all the functions exposed in the CoreIssuance
               * extension.
               */
              contract ICoreIssuance {
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Exchange components for Set tokens, accepting any owner
                   *
                   * @param  _owner        Address to use tokens from
                   * @param  _recipient    Address to issue Set to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueInternal(
                      address _owner,
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      internal;
              
                  /**
                   * Converts recipient's components into Set Tokens held directly in Vault
                   *
                   * @param _recipient    Address to issue to
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to issue
                   */
                  function issueInVaultInternal(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      internal;
              
                  /**
                   * Exchange Set tokens for underlying components
                   *
                   * @param _burnAddress       Address to burn tokens from
                   * @param _incrementAddress  Address to increment component tokens to
                   * @param _set               Address of the Set to redeem
                   * @param _quantity          Number of tokens to redeem
                   */
                  function redeemInternal(
                      address _burnAddress,
                      address _incrementAddress,
                      address _set,
                      uint256 _quantity
                  )
                      internal;
              }
              
              // File: contracts/core/extensions/CoreModuleInteraction.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              /**
               * @title CoreModularInteraction
               * @author Set Protocol
               *
               * Extension used to expose internal accounting and issuance functions, vault, and proxy functions
               * to modules.
               */
              contract CoreModuleInteraction is
                  ICoreAccounting,
                  ICoreIssuance,
                  CoreState,
                  ReentrancyGuard
              {
                  modifier onlyModule() {
                      onlyModuleCallable();
                      _;
                  }
              
                  function onlyModuleCallable() internal view {
                      require(
                          state.validModules[msg.sender],
                          "OnlyModule"
                      );
                  }
              
                  /**
                   * Exposes internal function that deposits tokens to the vault, exposed to system
                   * modules. Quantities should be in the order of the addresses of the tokens being
                   * deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _token             Address of the token being deposited
                   * @param  _quantity          Amount of tokens to deposit
                   */
                  function depositModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external
                      onlyModule
                  {
                      address[] memory tokenArray = new address[](1);
                      tokenArray[0] = _token;
              
                      uint256[] memory quantityArray = new uint256[](1);
                      quantityArray[0] = _quantity;
              
                      batchDepositInternal(
                          _from,
                          _to,
                          tokenArray,
                          quantityArray
                      );
                  }
              
                  /**
                   * Exposes internal function that deposits multiple tokens to the vault, exposed to system
                   * modules. Quantities should be in the order of the addresses of the tokens being
                   * deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _tokens            Array of the addresses of the tokens being deposited
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDepositModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyModule
                  {
                      batchDepositInternal(
                          _from,
                          _to,
                          _tokens,
                          _quantities
                      );
                  }
              
                  /**
                   * Exposes internal function that withdraws multiple tokens to the vault, exposed to system
                   * modules. Quantities should be in the order of the addresses of the tokens being
                   * withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _token             Address of the token being withdrawn
                   * @param  _quantity          Amount of tokens to withdraw
                   */
                  function withdrawModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external
                      onlyModule
                  {
                      address[] memory tokenArray = new address[](1);
                      tokenArray[0] = _token;
              
                      uint256[] memory quantityArray = new uint256[](1);
                      quantityArray[0] = _quantity;
              
                      batchWithdrawInternal(
                          _from,
                          _to,
                          tokenArray,
                          quantityArray
                      );
                  }
              
                  /**
                   * Exposes internal function that withdraws multiple tokens from the vault, to system
                   * modules. Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _tokens            Array of the addresses of the tokens being withdrawn
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdrawModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyModule
                  {
                      batchWithdrawInternal(
                          _from,
                          _to,
                          _tokens,
                          _quantities
                      );
                  }
              
                  /**
                   * Expose internal function that exchanges components for Set tokens,
                   * accepting any owner, to system modules
                   *
                   * @param  _componentOwner  Address to use tokens from
                   * @param  _setRecipient    Address to issue Set to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueModule(
                      address _componentOwner,
                      address _setRecipient,
                      address _set,
                      uint256 _quantity
                  )
                      external
                      onlyModule
                  {
                      issueInternal(
                          _componentOwner,
                          _setRecipient,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Converts recipient's components into Set Token's held directly in Vault
                   *
                   * @param _recipient    Address to issue to
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function issueInVaultModule(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external
                      onlyModule
                  {
                      issueInVaultInternal(
                          _recipient,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Expose internal function that exchanges Set tokens for components,
                   * accepting any owner, to system modules
                   *
                   * @param  _burnAddress         Address to burn token from
                   * @param  _incrementAddress    Address to increment component tokens to
                   * @param  _set                 Address of the Set to redeem
                   * @param  _quantity            Number of tokens to redeem
                   */
                  function redeemModule(
                      address _burnAddress,
                      address _incrementAddress,
                      address _set,
                      uint256 _quantity
                  )
                      external
                      onlyModule
                  {
                      redeemInternal(
                          _burnAddress,
                          _incrementAddress,
                          _set,
                          _quantity
                      );
                  }
              
                  /**
                   * Expose vault function that increments user's balance in the vault.
                   * Available to system modules
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyModule
                  {
                      state.vaultInstance.batchIncrementTokenOwner(
                          _tokens,
                          _owner,
                          _quantities
                      );
                  }
              
                  /**
                   * Expose vault function that decrement user's balance in the vault
                   * Only available to system modules.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyModule
                  {
                      state.vaultInstance.batchDecrementTokenOwner(
                          _tokens,
                          _owner,
                          _quantities
                      );
                  }
              
                  /**
                   * Expose vault function that transfer vault balances between users
                   * Only available to system modules.
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalanceModule(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external
                      onlyModule
                  {
                      state.vaultInstance.batchTransferBalance(
                          _tokens,
                          _from,
                          _to,
                          _quantities
                      );
                  }
              
                  /**
                   * Transfers token from one address to another using the transfer proxy.
                   * Only available to system modules.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _quantity       The number of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function transferModule(
                      address _token,
                      uint256 _quantity,
                      address _from,
                      address _to
                  )
                      external
                      onlyModule
                  {
                      state.transferProxyInstance.transfer(
                          _token,
                          _quantity,
                          _from,
                          _to
                      );
                  }
              
                  /**
                   * Expose transfer proxy function to transfer tokens from one address to another
                   * Only available to system modules.
                   *
                   * @param  _tokens         The addresses of the ERC20 token
                   * @param  _quantities     The numbers of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function batchTransferModule(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities,
                      address _from,
                      address _to
                  )
                      external
                      onlyModule
                  {
                      state.transferProxyInstance.batchTransfer(
                          _tokens,
                          _quantities,
                          _from,
                          _to
                      );
                  }
              }
              
              // File: contracts/core/Core.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              /**
               * @title Core
               * @author Set Protocol
               *
               * The Core contract acts as a coordinator handling issuing, redeeming, and
               * creating Sets, as well as all collateral flows throughout the system. Core
               * is also responsible for tracking state and exposing methods to modules
               */
               /* solium-disable-next-line no-empty-blocks */
              contract Core is
                  CoreAccounting,
                  CoreAdmin,
                  CoreFactory,
                  CoreIssuance,
                  CoreModuleInteraction
              {
                  /**
                   * Constructor function for Core
                   *
                   * @param _transferProxy       The address of the transfer proxy
                   * @param _vault               The address of the vault
                   */
                  constructor(
                      address _transferProxy,
                      address _vault
                  )
                      public
                  {
                      // Commit passed address to transferProxyAddress state variable
                      state.transferProxy = _transferProxy;
              
                      // Instantiate instance of transferProxy
                      state.transferProxyInstance = ITransferProxy(_transferProxy);
              
                      // Commit passed address to vault state variable
                      state.vault = _vault;
              
                      // Instantiate instance of vault
                      state.vaultInstance = IVault(_vault);
                  }
              }

              File 5 of 8: CoreIssuanceLibrary
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: contracts/core/interfaces/IVault.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IVault
               * @author Set Protocol
               *
               * The IVault interface provides a light-weight, structured way to interact with the Vault
               * contract from another contract.
               */
              interface IVault {
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer token to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function withdrawTo(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Increment quantity owned of a token for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to attribute to owner
                   */
                  function incrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Decrement quantity owned of a token for a given address. Can only
                   * be called by authorized core contracts.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _owner           The address of the token owner
                   * @param  _quantity        The number of tokens to deattribute to owner
                   */
                  function decrementTokenOwner(
                      address _token,
                      address _owner,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _token          Address of token being transferred
                   * @param  _from           Address token being transferred from
                   * @param  _to             Address token being transferred to
                   * @param  _quantity       Amount of tokens being transferred
                   */
              
                  function transferBalance(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
              
                  /*
                   * Withdraws user's unassociated tokens to user account. Can only be
                   * called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchWithdrawTo(
                      address[] calldata _tokens,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Increment quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Decrements quantites owned of a collection of tokens for a given address. Can
                   * only be called by authorized core contracts.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwner(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                 /**
                   * Transfers tokens associated with one account to another account in the vault
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalance(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /*
                   * Get balance of particular contract for owner.
                   *
                   * @param  _token    The address of the ERC20 token
                   * @param  _owner    The address of the token owner
                   */
                  function getOwnerBalance(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256);
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/core/lib/CoreIssuanceLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              pragma experimental "ABIEncoderV2";
              
              
              
              
              
              /**
               * @title CoreIssuanceLibrary
               * @author Set Protocol
               *
               * This library contains functions for calculating deposit, withdrawal,and transfer quantities
               */
              library CoreIssuanceLibrary {
              
                  using SafeMath for uint256;
              
                  /**
                   * Calculate the quantities required to deposit and decrement during issuance. Takes into account
                   * the tokens an owner already has in the vault.
                   *
                   * @param _components                           Addresses of components
                   * @param _componentQuantities                  Component quantities to increment and withdraw
                   * @param _owner                                Address to deposit and decrement quantities from
                   * @param _vault                                Address to vault
                   * @return uint256[] decrementQuantities        Quantities to decrement from vault
                   * @return uint256[] depositQuantities          Quantities to deposit into the vault
                   */
                  function calculateDepositAndDecrementQuantities(
                      address[] calldata _components,
                      uint256[] calldata _componentQuantities,
                      address _owner,
                      address _vault
                  )
                      external
                      view
                      returns (
                          uint256[] memory /* decrementQuantities */,
                          uint256[] memory /* depositQuantities */
                      )
                  {
                      uint256 componentCount = _components.length;
                      uint256[] memory decrementTokenOwnerValues = new uint256[](componentCount);
                      uint256[] memory depositQuantities = new uint256[](componentCount);
              
                      for (uint256 i = 0; i < componentCount; i++) {
                          // Fetch component quantity in vault
                          uint256 vaultBalance = IVault(_vault).getOwnerBalance(
                              _components[i],
                              _owner
                          );
              
                          // If the vault holds enough components, decrement the full amount
                          if (vaultBalance >= _componentQuantities[i]) {
                              decrementTokenOwnerValues[i] = _componentQuantities[i];
                          } else {
                              // User has less than required amount, decrement the vault by full balance
                              if (vaultBalance > 0) {
                                  decrementTokenOwnerValues[i] = vaultBalance;
                              }
              
                              depositQuantities[i] = _componentQuantities[i].sub(vaultBalance);
                          }
                      }
              
                      return (
                          decrementTokenOwnerValues,
                          depositQuantities
                      );
                  }
              
                  /**
                   * Calculate the quantities required to withdraw and increment during redeem and withdraw. Takes into
                   * account a bitmask exclusion parameter.
                   *
                   * @param _componentQuantities                  Component quantities to increment and withdraw
                   * @param _toExclude                            Mask of indexes of tokens to exclude from withdrawing
                   * @return uint256[] incrementQuantities        Quantities to increment in vault
                   * @return uint256[] withdrawQuantities         Quantities to withdraw from vault
                   */
                  function calculateWithdrawAndIncrementQuantities(
                      uint256[] calldata _componentQuantities,
                      uint256 _toExclude
                  )
                      external
                      pure
                      returns (
                          uint256[] memory /* incrementQuantities */,
                          uint256[] memory /* withdrawQuantities */
                      )
                  {
                      uint256 componentCount = _componentQuantities.length;
                      uint256[] memory incrementTokenOwnerValues = new uint256[](componentCount);
                      uint256[] memory withdrawToValues = new uint256[](componentCount);
              
                      // Loop through and decrement vault balances for the set, withdrawing if requested
                      for (uint256 i = 0; i < componentCount; i++) {
                          // Calculate bit index of current component
                          uint256 componentBitIndex = CommonMath.safePower(2, i);
              
                          // Transfer to user unless component index is included in _toExclude
                          if ((_toExclude & componentBitIndex) != 0) {
                              incrementTokenOwnerValues[i] = _componentQuantities[i];
                          } else {
                              withdrawToValues[i] = _componentQuantities[i];
                          }
                      }
              
                      return (
                          incrementTokenOwnerValues,
                          withdrawToValues
                      );
                  }
              
                  /**
                   * Calculate the required component quantities required for issuance or rdemption for a given
                   * quantity of Set Tokens
                   *
                   * @param _componentUnits   The units of the component token
                   * @param _naturalUnit      The natural unit of the Set token
                   * @param _quantity         The number of tokens being redeem
                   * @return uint256[]        Required quantities in base units of components
                   */
                  function calculateRequiredComponentQuantities(
                      uint256[] calldata _componentUnits,
                      uint256 _naturalUnit,
                      uint256 _quantity
                  )
                      external
                      pure
                      returns (uint256[] memory)
                  {
                      require(
                          _quantity.mod(_naturalUnit) == 0,
                          "CoreIssuanceLibrary: Quantity must be a multiple of nat unit"
                      );
              
                      uint256[] memory tokenValues = new uint256[](_componentUnits.length);
              
                      // Transfer the underlying tokens to the corresponding token balances
                      for (uint256 i = 0; i < _componentUnits.length; i++) {
                          tokenValues[i] = _quantity.div(_naturalUnit).mul(_componentUnits[i]);
                      }
              
                      return tokenValues;
                  }
              
              }

              File 6 of 8: TransferProxy
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/ownership/Ownable.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Ownable
               * @dev The Ownable contract has an owner address, and provides basic authorization control
               * functions, this simplifies the implementation of "user permissions".
               */
              contract Ownable {
                  address private _owner;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                   * account.
                   */
                  constructor () internal {
                      _owner = msg.sender;
                      emit OwnershipTransferred(address(0), _owner);
                  }
              
                  /**
                   * @return the address of the owner.
                   */
                  function owner() public view returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(isOwner());
                      _;
                  }
              
                  /**
                   * @return true if `msg.sender` is the owner of the contract.
                   */
                  function isOwner() public view returns (bool) {
                      return msg.sender == _owner;
                  }
              
                  /**
                   * @dev Allows the current owner to relinquish control of the contract.
                   * It will not be possible to call the functions with the `onlyOwner`
                   * modifier anymore.
                   * @notice Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = address(0);
                  }
              
                  /**
                   * @dev Allows the current owner to transfer control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function transferOwnership(address newOwner) public onlyOwner {
                      _transferOwnership(newOwner);
                  }
              
                  /**
                   * @dev Transfers control of the contract to a newOwner.
                   * @param newOwner The address to transfer ownership to.
                   */
                  function _transferOwnership(address newOwner) internal {
                      require(newOwner != address(0));
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              // File: contracts/lib/AddressArrayUtils.sol
              
              // Pulled in from Cryptofin Solidity package in order to control Solidity compiler version
              // https://github.com/cryptofinlabs/cryptofin-solidity/blob/master/contracts/array-utils/AddressArrayUtils.sol
              
              pragma solidity 0.5.7;
              
              
              library AddressArrayUtils {
              
                  /**
                   * Finds the index of the first occurrence of the given element.
                   * @param A The input array to search
                   * @param a The value to find
                   * @return Returns (index and isIn) for the first occurrence starting from index 0
                   */
                  function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length; i++) {
                          if (A[i] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                  * Returns true if the value is present in the list. Uses indexOf internally.
                  * @param A The input array to search
                  * @param a The value to find
                  * @return Returns isIn for the first occurrence starting from index 0
                  */
                  function contains(address[] memory A, address a) internal pure returns (bool) {
                      bool isIn;
                      (, isIn) = indexOf(A, a);
                      return isIn;
                  }
              
                  /// @return Returns index and isIn for the first occurrence starting from
                  /// end
                  function indexOfFromEnd(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = length; i > 0; i--) {
                          if (A[i - 1] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                   * Returns the combination of the two arrays
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A extended by B
                   */
                  function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 aLength = A.length;
                      uint256 bLength = B.length;
                      address[] memory newAddresses = new address[](aLength + bLength);
                      for (uint256 i = 0; i < aLength; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = 0; j < bLength; j++) {
                          newAddresses[aLength + j] = B[j];
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the array with a appended to A.
                   * @param A The first array
                   * @param a The value to append
                   * @return Returns A appended by a
                   */
                  function append(address[] memory A, address a) internal pure returns (address[] memory) {
                      address[] memory newAddresses = new address[](A.length + 1);
                      for (uint256 i = 0; i < A.length; i++) {
                          newAddresses[i] = A[i];
                      }
                      newAddresses[A.length] = a;
                      return newAddresses;
                  }
              
                  /**
                   * Returns the combination of two storage arrays.
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A appended by a
                   */
                  function sExtend(address[] storage A, address[] storage B) internal {
                      uint256 length = B.length;
                      for (uint256 i = 0; i < length; i++) {
                          A.push(B[i]);
                      }
                  }
              
                  /**
                   * Returns the intersection of two arrays. Arrays are treated as collections, so duplicates are kept.
                   * @param A The first array
                   * @param B The second array
                   * @return The intersection of the two arrays
                   */
                  function intersect(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 newLength = 0;
                      for (uint256 i = 0; i < length; i++) {
                          if (contains(B, A[i])) {
                              includeMap[i] = true;
                              newLength++;
                          }
                      }
                      address[] memory newAddresses = new address[](newLength);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the union of the two arrays. Order is not guaranteed.
                   * @param A The first array
                   * @param B The second array
                   * @return The union of the two arrays
                   */
                  function union(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      address[] memory leftDifference = difference(A, B);
                      address[] memory rightDifference = difference(B, A);
                      address[] memory intersection = intersect(A, B);
                      return extend(leftDifference, extend(intersection, rightDifference));
                  }
              
                  /**
                   * Alternate implementation
                   * Assumes there are no duplicates
                   */
                  function unionB(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      bool[] memory includeMap = new bool[](A.length + B.length);
                      uint256 count = 0;
                      for (uint256 i = 0; i < A.length; i++) {
                          includeMap[i] = true;
                          count++;
                      }
                      for (uint256 j = 0; j < B.length; j++) {
                          if (!contains(A, B[j])) {
                              includeMap[A.length + j] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 k = 0;
                      for (uint256 m = 0; m < A.length; m++) {
                          if (includeMap[m]) {
                              newAddresses[k] = A[m];
                              k++;
                          }
                      }
                      for (uint256 n = 0; n < B.length; n++) {
                          if (includeMap[A.length + n]) {
                              newAddresses[k] = B[n];
                              k++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Computes the difference of two arrays. Assumes there are no duplicates.
                   * @param A The first array
                   * @param B The second array
                   * @return The difference of the two arrays
                   */
                  function difference(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 count = 0;
                      // First count the new length because can't push for in-memory arrays
                      for (uint256 i = 0; i < length; i++) {
                          address e = A[i];
                          if (!contains(B, e)) {
                              includeMap[i] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                  * @dev Reverses storage array in place
                  */
                  function sReverse(address[] storage A) internal {
                      address t;
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length / 2; i++) {
                          t = A[i];
                          A[i] = A[A.length - i - 1];
                          A[A.length - i - 1] = t;
                      }
                  }
              
                  /**
                  * Removes specified index from array
                  * Resulting ordering is not guaranteed
                  * @return Returns the new array and the removed entry
                  */
                  function pop(address[] memory A, uint256 index)
                      internal
                      pure
                      returns (address[] memory, address)
                  {
                      uint256 length = A.length;
                      address[] memory newAddresses = new address[](length - 1);
                      for (uint256 i = 0; i < index; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = index + 1; j < length; j++) {
                          newAddresses[j - 1] = A[j];
                      }
                      return (newAddresses, A[index]);
                  }
              
                  /**
                   * @return Returns the new array
                   */
                  function remove(address[] memory A, address a)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert();
                      } else {
                          (address[] memory _A,) = pop(A, index);
                          return _A;
                      }
                  }
              
                  function sPop(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      for (uint256 i = index; i < length - 1; i++) {
                          A[i] = A[i + 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                  * Deletes address at index and fills the spot with the last address.
                  * Order is not preserved.
                  * @return Returns the removed entry
                  */
                  function sPopCheap(address[] storage A, uint256 index) internal returns (address) {
                      uint256 length = A.length;
                      if (index >= length) {
                          revert("Error: index out of bounds");
                      }
                      address entry = A[index];
                      if (index != length - 1) {
                          A[index] = A[length - 1];
                          delete A[length - 1];
                      }
                      A.length--;
                      return entry;
                  }
              
                  /**
                   * Deletes address at index. Works by swapping it with the last address, then deleting.
                   * Order is not preserved
                   * @param A Storage array to remove from
                   */
                  function sRemoveCheap(address[] storage A, address a) internal {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert("Error: entry not found");
                      } else {
                          sPopCheap(A, index);
                          return;
                      }
                  }
              
                  /**
                   * Returns whether or not there's a duplicate. Runs in O(n^2).
                   * @param A Array to search
                   * @return Returns true if duplicate, false otherwise
                   */
                  function hasDuplicate(address[] memory A) internal pure returns (bool) {
                      if (A.length == 0) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length - 1; i++) {
                          for (uint256 j = i + 1; j < A.length; j++) {
                              if (A[i] == A[j]) {
                                  return true;
                              }
                          }
                      }
                      return false;
                  }
              
                  /**
                   * Returns whether the two arrays are equal.
                   * @param A The first array
                   * @param B The second array
                   * @return True is the arrays are equal, false if not.
                   */
                  function isEqual(address[] memory A, address[] memory B) internal pure returns (bool) {
                      if (A.length != B.length) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length; i++) {
                          if (A[i] != B[i]) {
                              return false;
                          }
                      }
                      return true;
                  }
              
                  /**
                   * Returns the elements indexed at indexArray.
                   * @param A The array to index
                   * @param indexArray The array to use to index
                   * @return Returns array containing elements indexed at indexArray
                   */
                  function argGet(address[] memory A, uint256[] memory indexArray)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      address[] memory array = new address[](indexArray.length);
                      for (uint256 i = 0; i < indexArray.length; i++) {
                          array[i] = A[indexArray[i]];
                      }
                      return array;
                  }
              
              }
              
              // File: contracts/lib/TimeLockUpgrade.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title TimeLockUpgrade
               * @author Set Protocol
               *
               * The TimeLockUpgrade contract contains a modifier for handling minimum time period updates
               */
              contract TimeLockUpgrade is
                  Ownable
              {
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  // Timelock Upgrade Period in seconds
                  uint256 public timeLockPeriod;
              
                  // Mapping of upgradable units and initialized timelock
                  mapping(bytes32 => uint256) public timeLockedUpgrades;
              
                  /* ============ Events ============ */
              
                  event UpgradeRegistered(
                      bytes32 _upgradeHash,
                      uint256 _timestamp
                  );
              
                  /* ============ Modifiers ============ */
              
                  modifier timeLockUpgrade() {
                      // If the time lock period is 0, then allow non-timebound upgrades.
                      // This is useful for initialization of the protocol and for testing.
                      if (timeLockPeriod == 0) {
                          _;
              
                          return;
                      }
              
                      // The upgrade hash is defined by the hash of the transaction call data,
                      // which uniquely identifies the function as well as the passed in arguments.
                      bytes32 upgradeHash = keccak256(
                          abi.encodePacked(
                              msg.data
                          )
                      );
              
                      uint256 registrationTime = timeLockedUpgrades[upgradeHash];
              
                      // If the upgrade hasn't been registered, register with the current time.
                      if (registrationTime == 0) {
                          timeLockedUpgrades[upgradeHash] = block.timestamp;
              
                          emit UpgradeRegistered(
                              upgradeHash,
                              block.timestamp
                          );
              
                          return;
                      }
              
                      require(
                          block.timestamp >= registrationTime.add(timeLockPeriod),
                          "TimeLockUpgrade: Time lock period must have elapsed."
                      );
              
                      // Reset the timestamp to 0
                      timeLockedUpgrades[upgradeHash] = 0;
              
                      // Run the rest of the upgrades
                      _;
                  }
              
                  /* ============ Function ============ */
              
                  /**
                   * Change timeLockPeriod period. Generally called after initially settings have been set up.
                   *
                   * @param  _timeLockPeriod   Time in seconds that upgrades need to be evaluated before execution
                   */
                  function setTimeLockPeriod(
                      uint256 _timeLockPeriod
                  )
                      external
                      onlyOwner
                  {
                      // Only allow setting of the timeLockPeriod if the period is greater than the existing
                      require(
                          _timeLockPeriod > timeLockPeriod,
                          "TimeLockUpgrade: New period must be greater than existing"
                      );
              
                      timeLockPeriod = _timeLockPeriod;
                  }
              }
              
              // File: contracts/lib/Authorizable.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              /**
               * @title Authorizable
               * @author Set Protocol
               *
               * The Authorizable contract is an inherited contract that sets permissions on certain function calls
               * through the onlyAuthorized modifier. Permissions can be managed only by the Owner of the contract.
               */
              contract Authorizable is
                  Ownable,
                  TimeLockUpgrade
              {
                  using SafeMath for uint256;
                  using AddressArrayUtils for address[];
              
                  /* ============ State Variables ============ */
              
                  // Mapping of addresses to bool indicator of authorization
                  mapping (address => bool) public authorized;
              
                  // Array of authorized addresses
                  address[] public authorities;
              
                  /* ============ Modifiers ============ */
              
                  // Only authorized addresses can invoke functions with this modifier.
                  modifier onlyAuthorized {
                      require(
                          authorized[msg.sender],
                          "Authorizable.onlyAuthorized: Sender not included in authorities"
                      );
                      _;
                  }
              
                  /* ============ Events ============ */
              
                  // Event emitted when new address is authorized.
                  event AddressAuthorized (
                      address indexed authAddress,
                      address authorizedBy
                  );
              
                  // Event emitted when address is deauthorized.
                  event AuthorizedAddressRemoved (
                      address indexed addressRemoved,
                      address authorizedBy
                  );
              
                  /* ============ Setters ============ */
              
                  /**
                   * Add authorized address to contract. Can only be set by owner.
                   *
                   * @param  _authTarget   The address of the new authorized contract
                   */
              
                  function addAuthorizedAddress(address _authTarget)
                      external
                      onlyOwner
                      timeLockUpgrade
                  {
                      // Require that address is not already authorized
                      require(
                          !authorized[_authTarget],
                          "Authorizable.addAuthorizedAddress: Address already registered"
                      );
              
                      // Set address authority to true
                      authorized[_authTarget] = true;
              
                      // Add address to authorities array
                      authorities.push(_authTarget);
              
                      // Emit authorized address event
                      emit AddressAuthorized(
                          _authTarget,
                          msg.sender
                      );
                  }
              
                  /**
                   * Remove authorized address from contract. Can only be set by owner.
                   *
                   * @param  _authTarget   The address to be de-permissioned
                   */
              
                  function removeAuthorizedAddress(address _authTarget)
                      external
                      onlyOwner
                  {
                      // Require address is authorized
                      require(
                          authorized[_authTarget],
                          "Authorizable.removeAuthorizedAddress: Address not authorized"
                      );
              
                      // Delete address from authorized mapping
                      authorized[_authTarget] = false;
              
                      authorities = authorities.remove(_authTarget);
              
                      // Emit AuthorizedAddressRemoved event.
                      emit AuthorizedAddressRemoved(
                          _authTarget,
                          msg.sender
                      );
                  }
              
                  /* ============ Getters ============ */
              
                  /**
                   * Get array of authorized addresses.
                   *
                   * @return address[]   Array of authorized addresses
                   */
                  function getAuthorizedAddresses()
                      external
                      view
                      returns (address[] memory)
                  {
                      // Return array of authorized addresses
                      return authorities;
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/lib/IERC20.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title IERC20
               * @author Set Protocol
               *
               * Interface for using ERC20 Tokens. This interface is needed to interact with tokens that are not
               * fully ERC20 compliant and return something other than true on successful transfers.
               */
              interface IERC20 {
                  function balanceOf(
                      address _owner
                  )
                      external
                      view
                      returns (uint256);
              
                  function allowance(
                      address _owner,
                      address _spender
                  )
                      external
                      view
                      returns (uint256);
              
                  function transfer(
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  function transferFrom(
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  function approve(
                      address _spender,
                      uint256 _quantity
                  )
                      external
                      returns (bool);
              }
              
              // File: contracts/lib/ERC20Wrapper.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title ERC20Wrapper
               * @author Set Protocol
               *
               * This library contains functions for interacting wtih ERC20 tokens, even those not fully compliant.
               * For all functions we will only accept tokens that return a null or true value, any other values will
               * cause the operation to revert.
               */
              library ERC20Wrapper {
              
                  // ============ Internal Functions ============
              
                  /**
                   * Check balance owner's balance of ERC20 token
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The owner who's balance is being checked
                   * @return  uint256        The _owner's amount of tokens
                   */
                  function balanceOf(
                      address _token,
                      address _owner
                  )
                      external
                      view
                      returns (uint256)
                  {
                      return IERC20(_token).balanceOf(_owner);
                  }
              
                  /**
                   * Checks spender's allowance to use token's on owner's behalf.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The token owner address
                   * @param  _spender        The address the allowance is being checked on
                   * @return  uint256        The spender's allowance on behalf of owner
                   */
                  function allowance(
                      address _token,
                      address _owner,
                      address _spender
                  )
                      internal
                      view
                      returns (uint256)
                  {
                      return IERC20(_token).allowance(_owner, _spender);
                  }
              
                  /**
                   * Transfers tokens from an address. Handle's tokens that return true or null.
                   * If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _to             The address to transfer to
                   * @param  _quantity       The amount of tokens to transfer
                   */
                  function transfer(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external
                  {
                      IERC20(_token).transfer(_to, _quantity);
              
                      // Check that transfer returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.transfer: Bad return value"
                      );
                  }
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Handle's tokens that return true or null. If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   * @param  _quantity       The number of tokens to transfer
                   */
                  function transferFrom(
                      address _token,
                      address _from,
                      address _to,
                      uint256 _quantity
                  )
                      external
                  {
                      IERC20(_token).transferFrom(_from, _to, _quantity);
              
                      // Check that transferFrom returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.transferFrom: Bad return value"
                      );
                  }
              
                  /**
                   * Grants spender ability to spend on owner's behalf.
                   * Handle's tokens that return true or null. If other value returned, reverts.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _spender        The address to approve for transfer
                   * @param  _quantity       The amount of tokens to approve spender for
                   */
                  function approve(
                      address _token,
                      address _spender,
                      uint256 _quantity
                  )
                      internal
                  {
                      IERC20(_token).approve(_spender, _quantity);
              
                      // Check that approve returns true or null
                      require(
                          checkSuccess(),
                          "ERC20Wrapper.approve: Bad return value"
                      );
                  }
              
                  /**
                   * Ensure's the owner has granted enough allowance for system to
                   * transfer tokens.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _owner          The address of the token owner
                   * @param  _spender        The address to grant/check allowance for
                   * @param  _quantity       The amount to see if allowed for
                   */
                  function ensureAllowance(
                      address _token,
                      address _owner,
                      address _spender,
                      uint256 _quantity
                  )
                      internal
                  {
                      uint256 currentAllowance = allowance(_token, _owner, _spender);
                      if (currentAllowance < _quantity) {
                          approve(
                              _token,
                              _spender,
                              CommonMath.maxUInt256()
                          );
                      }
                  }
              
                  // ============ Private Functions ============
              
                  /**
                   * Checks the return value of the previous function up to 32 bytes. Returns true if the previous
                   * function returned 0 bytes or 1.
                   */
                  function checkSuccess(
                  )
                      private
                      pure
                      returns (bool)
                  {
                      // default to failure
                      uint256 returnValue = 0;
              
                      assembly {
                          // check number of bytes returned from last function call
                          switch returndatasize
              
                          // no bytes returned: assume success
                          case 0x0 {
                              returnValue := 1
                          }
              
                          // 32 bytes returned
                          case 0x20 {
                              // copy 32 bytes into scratch space
                              returndatacopy(0x0, 0x0, 0x20)
              
                              // load those bytes into returnValue
                              returnValue := mload(0x0)
                          }
              
                          // not sure what was returned: dont mark as success
                          default { }
                      }
              
                      // check if returned value is one or nothing
                      return returnValue == 1;
                  }
              }
              
              // File: contracts/core/TransferProxy.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              /**
               * @title TransferProxy
               * @author Set Protocol
               *
               * The transferProxy contract is responsible for moving tokens through the system to
               * assist with issuance and usage from modules.
               */
              
              contract TransferProxy is
                  Authorizable
              {
                  using SafeMath for uint256;
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Can only be called by Core.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _quantity       The number of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function transfer(
                      address _token,
                      uint256 _quantity,
                      address _from,
                      address _to
                  )
                      public
                      onlyAuthorized
                  {
                      // Call specified ERC20 contract to transfer tokens (via proxy).
                      if (_quantity > 0) {
                          // Retrieve current balance of token for the receiver
                          uint256 existingBalance = ERC20Wrapper.balanceOf(
                              _token,
                              _to
                          );
              
                          ERC20Wrapper.transferFrom(
                              _token,
                              _from,
                              _to,
                              _quantity
                          );
              
                          // Get new balance of transferred token for receiver
                          uint256 newBalance = ERC20Wrapper.balanceOf(
                              _token,
                              _to
                          );
              
                          // Verify transfer quantity is reflected in balance
                          require(
                              newBalance == existingBalance.add(_quantity),
                              "TransferProxy.transfer: Invalid post transfer balance"
                          );
                      }
                  }
              
                  /**
                   * Transfers tokens from an address (that has set allowance on the proxy).
                   * Can only be called by Core.
                   *
                   * @param  _tokens         The addresses of the ERC20 token
                   * @param  _quantities     The numbers of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function batchTransfer(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities,
                      address _from,
                      address _to
                  )
                      external
                      onlyAuthorized
                  {
                      // Storing token count to local variable to save on invocation
                      uint256 tokenCount = _tokens.length;
              
                      // Confirm and empty _tokens array is not passed
                      require(
                          tokenCount > 0,
                          "TransferProxy.batchTransfer: Tokens must not be empty"
                      );
              
                      // Confirm there is one quantity for every token address
                      require(
                          tokenCount == _quantities.length,
                          "TransferProxy.batchTransfer: Tokens and quantities lengths mismatch"
                      );
              
                      for (uint256 i = 0; i < tokenCount; i++) {
                          if (_quantities[i] > 0) {
                              transfer(
                                  _tokens[i],
                                  _quantities[i],
                                  _from,
                                  _to
                              );
                          }
                      }
                  }
              
              }

              File 7 of 8: SetTokenFactory
              // File: contracts/lib/Bytes32Library.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              library Bytes32Library {
                  /**
                   * Converts a bytes32 data structure into a bytes array.
                   *
                   * @param  data       Piece of data encoded as bytes32
                   * @return bytes
                   */
                  function bytes32ToBytes(bytes32 data)
                      internal
                      pure
                      returns (bytes memory)
                  {
                      uint256 i = 0;
                      while (i < 32 && uint256(bytes32(data[i])) != 0) {
                          ++i;
                      }
                      bytes memory result = new bytes(i);
                      i = 0;
                      while (i < 32 && data[i] != 0) {
                          result[i] = data[i];
                          ++i;
                      }
                      return result;
                  }
              
                  /**
                   * Converts a piece of data encoded as bytes32 into a string.
                   *
                   * @param  data       Piece of data encoded as bytes32
                   * @return string
                   */
                  function bytes32ToString(bytes32 data)
                      internal
                      pure
                      returns (string memory)
                  {
                      bytes memory intermediate = bytes32ToBytes(data);
                      return string(abi.encodePacked(intermediate));
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title ERC20 interface
               * @dev see https://eips.ethereum.org/EIPS/eip-20
               */
              interface IERC20 {
                  function transfer(address to, uint256 value) external returns (bool);
              
                  function approve(address spender, uint256 value) external returns (bool);
              
                  function transferFrom(address from, address to, uint256 value) external returns (bool);
              
                  function totalSupply() external view returns (uint256);
              
                  function balanceOf(address who) external view returns (uint256);
              
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
              
              pragma solidity ^0.5.2;
              
              
              /**
               * @title ERC20Detailed token
               * @dev The decimals are only for visualization purposes.
               * All the operations are done using the smallest and indivisible token unit,
               * just as on Ethereum all the operations are done in wei.
               */
              contract ERC20Detailed is IERC20 {
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
              
                  constructor (string memory name, string memory symbol, uint8 decimals) public {
                      _name = name;
                      _symbol = symbol;
                      _decimals = decimals;
                  }
              
                  /**
                   * @return the name of the token.
                   */
                  function name() public view returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @return the symbol of the token.
                   */
                  function symbol() public view returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @return the number of decimals of the token.
                   */
                  function decimals() public view returns (uint8) {
                      return _decimals;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
              
              pragma solidity ^0.5.2;
              
              
              
              /**
               * @title Standard ERC20 token
               *
               * @dev Implementation of the basic standard token.
               * https://eips.ethereum.org/EIPS/eip-20
               * Originally based on code by FirstBlood:
               * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
               *
               * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
               * all accounts just by listening to said events. Note that this isn't required by the specification, and other
               * compliant implementations may not do it.
               */
              contract ERC20 is IERC20 {
                  using SafeMath for uint256;
              
                  mapping (address => uint256) private _balances;
              
                  mapping (address => mapping (address => uint256)) private _allowed;
              
                  uint256 private _totalSupply;
              
                  /**
                   * @dev Total number of tokens in existence
                   */
                  function totalSupply() public view returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev Gets the balance of the specified address.
                   * @param owner The address to query the balance of.
                   * @return A uint256 representing the amount owned by the passed address.
                   */
                  function balanceOf(address owner) public view returns (uint256) {
                      return _balances[owner];
                  }
              
                  /**
                   * @dev Function to check the amount of tokens that an owner allowed to a spender.
                   * @param owner address The address which owns the funds.
                   * @param spender address The address which will spend the funds.
                   * @return A uint256 specifying the amount of tokens still available for the spender.
                   */
                  function allowance(address owner, address spender) public view returns (uint256) {
                      return _allowed[owner][spender];
                  }
              
                  /**
                   * @dev Transfer token to a specified address
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function transfer(address to, uint256 value) public returns (bool) {
                      _transfer(msg.sender, to, value);
                      return true;
                  }
              
                  /**
                   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                   * Beware that changing an allowance with this method brings the risk that someone may use both the old
                   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
                   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   * @param spender The address which will spend the funds.
                   * @param value The amount of tokens to be spent.
                   */
                  function approve(address spender, uint256 value) public returns (bool) {
                      _approve(msg.sender, spender, value);
                      return true;
                  }
              
                  /**
                   * @dev Transfer tokens from one address to another.
                   * Note that while this function emits an Approval event, this is not required as per the specification,
                   * and other compliant implementations may not emit the event.
                   * @param from address The address which you want to send tokens from
                   * @param to address The address which you want to transfer to
                   * @param value uint256 the amount of tokens to be transferred
                   */
                  function transferFrom(address from, address to, uint256 value) public returns (bool) {
                      _transfer(from, to, value);
                      _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
                      return true;
                  }
              
                  /**
                   * @dev Increase the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To increment
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param addedValue The amount of tokens to increase the allowance by.
                   */
                  function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
                      return true;
                  }
              
                  /**
                   * @dev Decrease the amount of tokens that an owner allowed to a spender.
                   * approve should be called when _allowed[msg.sender][spender] == 0. To decrement
                   * allowed value is better to use this function to avoid 2 calls (and wait until
                   * the first transaction is mined)
                   * From MonolithDAO Token.sol
                   * Emits an Approval event.
                   * @param spender The address which will spend the funds.
                   * @param subtractedValue The amount of tokens to decrease the allowance by.
                   */
                  function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
                      _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
                      return true;
                  }
              
                  /**
                   * @dev Transfer token for a specified addresses
                   * @param from The address to transfer from.
                   * @param to The address to transfer to.
                   * @param value The amount to be transferred.
                   */
                  function _transfer(address from, address to, uint256 value) internal {
                      require(to != address(0));
              
                      _balances[from] = _balances[from].sub(value);
                      _balances[to] = _balances[to].add(value);
                      emit Transfer(from, to, value);
                  }
              
                  /**
                   * @dev Internal function that mints an amount of the token and assigns it to
                   * an account. This encapsulates the modification of balances such that the
                   * proper events are emitted.
                   * @param account The account that will receive the created tokens.
                   * @param value The amount that will be created.
                   */
                  function _mint(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.add(value);
                      _balances[account] = _balances[account].add(value);
                      emit Transfer(address(0), account, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account.
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burn(address account, uint256 value) internal {
                      require(account != address(0));
              
                      _totalSupply = _totalSupply.sub(value);
                      _balances[account] = _balances[account].sub(value);
                      emit Transfer(account, address(0), value);
                  }
              
                  /**
                   * @dev Approve an address to spend another addresses' tokens.
                   * @param owner The address that owns the tokens.
                   * @param spender The address that will spend the tokens.
                   * @param value The number of tokens that can be spent.
                   */
                  function _approve(address owner, address spender, uint256 value) internal {
                      require(spender != address(0));
                      require(owner != address(0));
              
                      _allowed[owner][spender] = value;
                      emit Approval(owner, spender, value);
                  }
              
                  /**
                   * @dev Internal function that burns an amount of the token of a given
                   * account, deducting from the sender's allowance for said account. Uses the
                   * internal burn function.
                   * Emits an Approval event (reflecting the reduced allowance).
                   * @param account The account whose tokens will be burnt.
                   * @param value The amount that will be burnt.
                   */
                  function _burnFrom(address account, uint256 value) internal {
                      _burn(account, value);
                      _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
                  }
              }
              
              // File: contracts/lib/CommonValidationsLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              library CommonValidationsLibrary {
              
                  /**
                   * Ensures that an address array is not empty.
                   *
                   * @param  _addressArray       Address array input
                   */
                  function validateNonEmpty(
                      address[] calldata _addressArray
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length > 0,
                          "Address array length must be > 0"
                      );
                  }
              
                  /**
                   * Ensures that an address array and uint256 array are equal length
                   *
                   * @param  _addressArray       Address array input
                   * @param  _uint256Array       Uint256 array input
                   */
                  function validateEqualLength(
                      address[] calldata _addressArray,
                      uint256[] calldata _uint256Array
                  )
                      external
                      pure
                  {
                      require(
                          _addressArray.length == _uint256Array.length,
                          "Input length mismatch"
                      );
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return 2 ** 256 - 1;
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
              }
              
              // File: contracts/core/interfaces/ISetFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ISetFactory
               * @author Set Protocol
               *
               * The ISetFactory interface provides operability for authorized contracts
               * to interact with SetTokenFactory
               */
              interface ISetFactory {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Return core address
                   *
                   * @return address        core address
                   */
                  function core()
                      external
                      returns (address);
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address[] calldata _components,
                      uint[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              }
              
              // File: contracts/core/tokens/SetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              /**
               * @title SetToken
               * @author Set Protocol
               *
               * Implementation of the basic Set token.
               */
              contract SetToken is
                  ERC20,
                  ERC20Detailed
              {
                  using SafeMath for uint256;
              
                  /* ============ State Variables ============ */
              
                  uint256 public naturalUnit;
                  address[] public components;
                  uint256[] public units;
              
                  // Mapping of componentHash to isComponent
                  mapping(address => bool) internal isComponent;
              
                  // Address of the Factory contract that created the SetToken
                  address public factory;
              
                  /* ============ Constructor ============ */
              
                  /**
                   * Constructor function for Set token
                   *
                   * As looping operations are expensive, checking for duplicates will be on the onus of the application developer
                   *
                   * @param _factory          The factory used to create the Set Token
                   * @param _components       A list of component address which you want to include
                   * @param _units            A list of quantities of each component (corresponds to the Set of _components)
                   * @param _naturalUnit      The minimum multiple of Sets that can be issued or redeemed
                   * @param _name             The Set's name
                   * @param _symbol           The Set's symbol
                   */
                  constructor(
                      address _factory,
                      address[] memory _components,
                      uint256[] memory _units,
                      uint256 _naturalUnit,
                      string memory _name,
                      string memory _symbol
                  )
                      public
                      ERC20Detailed(
                          _name,
                          _symbol,
                          18
                      )
                  {
                      // Storing count and unit counts to local variable to save on invocation
                      uint256 unitCount = _units.length;
              
                      // Require naturalUnit passed is greater than 0
                      require(
                          _naturalUnit > 0,
                          "SetToken.constructor: Natural unit must be positive"
                      );
              
                      // Confirm an empty _components array is not passed
                      CommonValidationsLibrary.validateNonEmpty(_components);
              
                      // Confirm there is one quantity for every token address
                      CommonValidationsLibrary.validateEqualLength(_components, _units);
              
                      // NOTE: It will be the onus of developers to check whether the addressExists
                      // are in fact ERC20 addresses
                      uint8 minDecimals = 18;
                      uint8 currentDecimals;
                      for (uint256 i = 0; i < unitCount; i++) {
                          // Check that all units are non-zero
                          uint256 currentUnits = _units[i];
                          require(
                              currentUnits > 0,
                              "SetToken.constructor: Units must be positive"
                          );
              
                          // Check that all addresses are non-zero
                          address currentComponent = _components[i];
                          require(
                              currentComponent != address(0),
                              "SetToken.constructor: Invalid component address"
                          );
              
                          // Figure out which of the components has the minimum decimal value
                          /* solium-disable-next-line security/no-low-level-calls */
                          (bool success, ) = currentComponent.call(abi.encodeWithSignature("decimals()"));
                          if (success) {
                              currentDecimals = ERC20Detailed(currentComponent).decimals();
                              minDecimals = currentDecimals < minDecimals ? currentDecimals : minDecimals;
                          } else {
                              // If one of the components does not implement decimals, we assume the worst
                              // and set minDecimals to 0
                              minDecimals = 0;
                          }
              
                          // Check the component has not already been added
                          require(
                              !tokenIsComponent(currentComponent),
                              "SetToken.constructor: Duplicated component"
                          );
              
                          // Add component to isComponent mapping
                          isComponent[currentComponent] = true;
              
                          // Add component data to components and units state variables
                          components.push(currentComponent);
                          units.push(currentUnits);
                      }
              
                      // This is the minimum natural unit possible for a Set with these components.
                      require(
                          _naturalUnit >= CommonMath.safePower(10, uint256(18).sub(minDecimals)),
                          "SetToken.constructor: Invalid natural unit"
                      );
              
                      factory = _factory;
                      naturalUnit = _naturalUnit;
                  }
              
                  /* ============ Public Functions ============ */
              
                  /*
                   * Mint set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external
                  {
                      // Check that function caller is Core
                      require(
                          msg.sender == ISetFactory(factory).core(),
                          "SetToken.mint: Sender must be core"
                      );
              
                      _mint(_issuer, _quantity);
                  }
              
                  /*
                   * Burn set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external
                  {
                      // Check that function caller is Core
                      require(
                          msg.sender == ISetFactory(factory).core(),
                          "SetToken.burn: Sender must be core"
                      );
              
                      _burn(_from, _quantity);
                  }
              
                  /*
                   * Get addresses of all components in the Set
                   *
                   * @return  componentAddresses       Array of component tokens
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory)
                  {
                      return components;
                  }
              
                  /*
                   * Get units of all tokens in Set
                   *
                   * @return  units       Array of component units
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory)
                  {
                      return units;
                  }
              
                  /*
                   * Validates address is member of Set's components
                   *
                   * @param  _tokenAddress     Address of token being checked
                   * @return  bool             Whether token is member of Set's components
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      public
                      view
                      returns (bool)
                  {
                      return isComponent[_tokenAddress];
                  }
              }
              
              // File: contracts/core/tokens/SetTokenFactory.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title SetTokenFactory
               * @author Set Protocol
               *
               * SetTokenFactory is a smart contract used to deploy new SetToken contracts.
               * SetTokens deployed by the factory can only have their mint and burn functions
               * called by Core
               */
              contract SetTokenFactory
              {
                  using Bytes32Library for bytes32;
              
                  /* ============ State Variables ============ */
              
                  // Address of the Core contract
                  address public core;
              
                  /* ============ Constructor ============ */
              
                  /**
                   * Set core constructor
                   *
                   * @param  _core   The address of deployed core contract
                   */
                  constructor(
                      address _core
                  )
                      public
                  {
                      core = _core;
                  }
              
                  /* ============ Public Functions ============ */
              
                  /**
                   * Deploys a new SetToken contract.
                   * Can only be called by authorized core contracts.
                   *
                   * @param  _components     The address of component tokens
                   * @param  _units          The units of each component token
                   * @param  _naturalUnit    The minimum unit to be issued or redeemed
                   * @param  _name           The bytes32 encoded name of the new Set
                   * @param  _symbol         The bytes32 encoded symbol of the new Set
                   * -- Unused callData param used to pass additional information to factories --
                   * @return setToken        The address of the newly created SetToken
                   */
                  function createSet(
                      address[] calldata _components,
                      uint256[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata
                  )
                      external
                      returns (address)
                  {
                      // Expecting caller to be Core
                      require(
                          msg.sender == core,
                          "SetTokenFactory.create: Sender must be core"
                      );
              
                      // Create a new SetToken contract
                      return address(
                          new SetToken(
                              address(this),
                              _components,
                              _units,
                              _naturalUnit,
                              _name.bytes32ToString(),
                              _symbol.bytes32ToString()
                          )
                      );
                  }
              }

              File 8 of 8: LinearAuctionLiquidator
              // File: openzeppelin-solidity/contracts/math/SafeMath.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title SafeMath
               * @dev Unsigned math operations with safety checks that revert on error
               */
              library SafeMath {
                  /**
                   * @dev Multiplies two unsigned integers, reverts on overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
                      if (a == 0) {
                          return 0;
                      }
              
                      uint256 c = a * b;
                      require(c / a == b);
              
                      return c;
                  }
              
                  /**
                   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      // Solidity only automatically asserts when dividing by 0
                      require(b > 0);
                      uint256 c = a / b;
                      // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              
                      return c;
                  }
              
                  /**
                   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a);
                      uint256 c = a - b;
              
                      return c;
                  }
              
                  /**
                   * @dev Adds two unsigned integers, reverts on overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a);
              
                      return c;
                  }
              
                  /**
                   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
                   * reverts when dividing by zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b != 0);
                      return a % b;
                  }
              }
              
              // File: contracts/core/interfaces/ICore.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title ICore
               * @author Set Protocol
               *
               * The ICore Contract defines all the functions exposed in the Core through its
               * various extensions and is a light weight way to interact with the contract.
               */
              interface ICore {
                  /**
                   * Return transferProxy address.
                   *
                   * @return address       transferProxy address
                   */
                  function transferProxy()
                      external
                      view
                      returns (address);
              
                  /**
                   * Return vault address.
                   *
                   * @return address       vault address
                   */
                  function vault()
                      external
                      view
                      returns (address);
              
                  /**
                   * Return address belonging to given exchangeId.
                   *
                   * @param  _exchangeId       ExchangeId number
                   * @return address           Address belonging to given exchangeId
                   */
                  function exchangeIds(
                      uint8 _exchangeId
                  )
                      external
                      view
                      returns (address);
              
                  /*
                   * Returns if valid set
                   *
                   * @return  bool      Returns true if Set created through Core and isn't disabled
                   */
                  function validSets(address)
                      external
                      view
                      returns (bool);
              
                  /*
                   * Returns if valid module
                   *
                   * @return  bool      Returns true if valid module
                   */
                  function validModules(address)
                      external
                      view
                      returns (bool);
              
                  /**
                   * Return boolean indicating if address is a valid Rebalancing Price Library.
                   *
                   * @param  _priceLibrary    Price library address
                   * @return bool             Boolean indicating if valid Price Library
                   */
                  function validPriceLibraries(
                      address _priceLibrary
                  )
                      external
                      view
                      returns (bool);
              
                  /**
                   * Exchanges components for Set Tokens
                   *
                   * @param  _set          Address of set to issue
                   * @param  _quantity     Quantity of set to issue
                   */
                  function issue(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Issues a specified Set for a specified quantity to the recipient
                   * using the caller's components from the wallet and vault.
                   *
                   * @param  _recipient    Address to issue to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Converts user's components into Set Tokens held directly in Vault instead of user's account
                   *
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function issueInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Function to convert Set Tokens into underlying components
                   *
                   * @param _set          The address of the Set token
                   * @param _quantity     The number of tokens to redeem. Should be multiple of natural unit.
                   */
                  function redeem(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Redeem Set token and return components to specified recipient. The components
                   * are left in the vault
                   *
                   * @param _recipient    Recipient of Set being issued
                   * @param _set          Address of the Set
                   * @param _quantity     Number of tokens to redeem
                   */
                  function redeemTo(
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Function to convert Set Tokens held in vault into underlying components
                   *
                   * @param _set          The address of the Set token
                   * @param _quantity     The number of tokens to redeem. Should be multiple of natural unit.
                   */
                  function redeemInVault(
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Composite method to redeem and withdraw with a single transaction
                   *
                   * Normally, you should expect to be able to withdraw all of the tokens.
                   * However, some have central abilities to freeze transfers (e.g. EOS). _toExclude
                   * allows you to optionally specify which component tokens to exclude when
                   * redeeming. They will remain in the vault under the users' addresses.
                   *
                   * @param _set          Address of the Set
                   * @param _to           Address to withdraw or attribute tokens to
                   * @param _quantity     Number of tokens to redeem
                   * @param _toExclude    Mask of indexes of tokens to exclude from withdrawing
                   */
                  function redeemAndWithdrawTo(
                      address _set,
                      address _to,
                      uint256 _quantity,
                      uint256 _toExclude
                  )
                      external;
              
                  /**
                   * Deposit multiple tokens to the vault. Quantities should be in the
                   * order of the addresses of the tokens being deposited.
                   *
                   * @param  _tokens           Array of the addresses of the ERC20 tokens
                   * @param  _quantities       Array of the number of tokens to deposit
                   */
                  function batchDeposit(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Withdraw multiple tokens from the vault. Quantities should be in the
                   * order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _tokens            Array of the addresses of the ERC20 tokens
                   * @param  _quantities        Array of the number of tokens to withdraw
                   */
                  function batchWithdraw(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Deposit any quantity of tokens into the vault.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _quantity        The number of tokens to deposit
                   */
                  function deposit(
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Withdraw a quantity of tokens from the vault.
                   *
                   * @param  _token           The address of the ERC20 token
                   * @param  _quantity        The number of tokens to withdraw
                   */
                  function withdraw(
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Transfer tokens associated with the sender's account in vault to another user's
                   * account in vault.
                   *
                   * @param  _token           Address of token being transferred
                   * @param  _to              Address of user receiving tokens
                   * @param  _quantity        Amount of tokens being transferred
                   */
                  function internalTransfer(
                      address _token,
                      address _to,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Deploys a new Set Token and adds it to the valid list of SetTokens
                   *
                   * @param  _factory              The address of the Factory to create from
                   * @param  _components           The address of component tokens
                   * @param  _units                The units of each component token
                   * @param  _naturalUnit          The minimum unit to be issued or redeemed
                   * @param  _name                 The bytes32 encoded name of the new Set
                   * @param  _symbol               The bytes32 encoded symbol of the new Set
                   * @param  _callData             Byte string containing additional call parameters
                   * @return setTokenAddress       The address of the new Set
                   */
                  function createSet(
                      address _factory,
                      address[] calldata _components,
                      uint256[] calldata _units,
                      uint256 _naturalUnit,
                      bytes32 _name,
                      bytes32 _symbol,
                      bytes calldata _callData
                  )
                      external
                      returns (address);
              
                  /**
                   * Exposes internal function that deposits a quantity of tokens to the vault and attributes
                   * the tokens respectively, to system modules.
                   *
                   * @param  _from            Address to transfer tokens from
                   * @param  _to              Address to credit for deposit
                   * @param  _token           Address of token being deposited
                   * @param  _quantity        Amount of tokens to deposit
                   */
                  function depositModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Exposes internal function that withdraws a quantity of tokens from the vault and
                   * deattributes the tokens respectively, to system modules.
                   *
                   * @param  _from            Address to decredit for withdraw
                   * @param  _to              Address to transfer tokens to
                   * @param  _token           Address of token being withdrawn
                   * @param  _quantity        Amount of tokens to withdraw
                   */
                  function withdrawModule(
                      address _from,
                      address _to,
                      address _token,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Exposes internal function that deposits multiple tokens to the vault, to system
                   * modules. Quantities should be in the order of the addresses of the tokens being
                   * deposited.
                   *
                   * @param  _from              Address to transfer tokens from
                   * @param  _to                Address to credit for deposits
                   * @param  _tokens            Array of the addresses of the tokens being deposited
                   * @param  _quantities        Array of the amounts of tokens to deposit
                   */
                  function batchDepositModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Exposes internal function that withdraws multiple tokens from the vault, to system
                   * modules. Quantities should be in the order of the addresses of the tokens being withdrawn.
                   *
                   * @param  _from              Address to decredit for withdrawals
                   * @param  _to                Address to transfer tokens to
                   * @param  _tokens            Array of the addresses of the tokens being withdrawn
                   * @param  _quantities        Array of the amounts of tokens to withdraw
                   */
                  function batchWithdrawModule(
                      address _from,
                      address _to,
                      address[] calldata _tokens,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose internal function that exchanges components for Set tokens,
                   * accepting any owner, to system modules
                   *
                   * @param  _owner        Address to use tokens from
                   * @param  _recipient    Address to issue Set to
                   * @param  _set          Address of the Set to issue
                   * @param  _quantity     Number of tokens to issue
                   */
                  function issueModule(
                      address _owner,
                      address _recipient,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Expose internal function that exchanges Set tokens for components,
                   * accepting any owner, to system modules
                   *
                   * @param  _burnAddress         Address to burn token from
                   * @param  _incrementAddress    Address to increment component tokens to
                   * @param  _set                 Address of the Set to redeem
                   * @param  _quantity            Number of tokens to redeem
                   */
                  function redeemModule(
                      address _burnAddress,
                      address _incrementAddress,
                      address _set,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                   * Expose vault function that increments user's balance in the vault.
                   * Available to system modules
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchIncrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose vault function that decrement user's balance in the vault
                   * Only available to system modules.
                   *
                   * @param  _tokens          The addresses of the ERC20 tokens
                   * @param  _owner           The address of the token owner
                   * @param  _quantities      The numbers of tokens to attribute to owner
                   */
                  function batchDecrementTokenOwnerModule(
                      address[] calldata _tokens,
                      address _owner,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Expose vault function that transfer vault balances between users
                   * Only available to system modules.
                   *
                   * @param  _tokens           Addresses of tokens being transferred
                   * @param  _from             Address tokens being transferred from
                   * @param  _to               Address tokens being transferred to
                   * @param  _quantities       Amounts of tokens being transferred
                   */
                  function batchTransferBalanceModule(
                      address[] calldata _tokens,
                      address _from,
                      address _to,
                      uint256[] calldata _quantities
                  )
                      external;
              
                  /**
                   * Transfers token from one address to another using the transfer proxy.
                   * Only available to system modules.
                   *
                   * @param  _token          The address of the ERC20 token
                   * @param  _quantity       The number of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function transferModule(
                      address _token,
                      uint256 _quantity,
                      address _from,
                      address _to
                  )
                      external;
              
                  /**
                   * Expose transfer proxy function to transfer tokens from one address to another
                   * Only available to system modules.
                   *
                   * @param  _tokens         The addresses of the ERC20 token
                   * @param  _quantities     The numbers of tokens to transfer
                   * @param  _from           The address to transfer from
                   * @param  _to             The address to transfer to
                   */
                  function batchTransferModule(
                      address[] calldata _tokens,
                      uint256[] calldata _quantities,
                      address _from,
                      address _to
                  )
                      external;
              }
              
              // File: contracts/core/interfaces/ISetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title ISetToken
               * @author Set Protocol
               *
               * The ISetToken interface provides a light-weight, structured way to interact with the
               * SetToken contract from another contract.
               */
              interface ISetToken {
              
                  /* ============ External Functions ============ */
              
                  /*
                   * Get natural unit of Set
                   *
                   * @return  uint256       Natural unit of Set
                   */
                  function naturalUnit()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get addresses of all components in the Set
                   *
                   * @return  componentAddresses       Array of component tokens
                   */
                  function getComponents()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get units of all tokens in Set
                   *
                   * @return  units       Array of component units
                   */
                  function getUnits()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Checks to make sure token is component of Set
                   *
                   * @param  _tokenAddress     Address of token being checked
                   * @return  bool             True if token is component of Set
                   */
                  function tokenIsComponent(
                      address _tokenAddress
                  )
                      external
                      view
                      returns (bool);
              
                  /*
                   * Mint set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _issuer      The address of the issuing account
                   * @param  _quantity    The number of sets to attribute to issuer
                   */
                  function mint(
                      address _issuer,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Burn set token for given address
                   * Can only be called by authorized contracts
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external;
              
                  /**
                  * Transfer token for a specified address
                  *
                  * @param to The address to transfer to.
                  * @param value The amount to be transferred.
                  */
                  function transfer(
                      address to,
                      uint256 value
                  )
                      external;
              }
              
              // File: contracts/core/lib/RebalancingLibrary.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title RebalancingLibrary
               * @author Set Protocol
               *
               * The RebalancingLibrary contains functions for facilitating the rebalancing process for
               * Rebalancing Set Tokens. Removes the old calculation functions
               *
               */
              library RebalancingLibrary {
              
                  /* ============ Enums ============ */
              
                  enum State { Default, Proposal, Rebalance, Drawdown }
              
                  /* ============ Structs ============ */
              
                  struct AuctionPriceParameters {
                      uint256 auctionStartTime;
                      uint256 auctionTimeToPivot;
                      uint256 auctionStartPrice;
                      uint256 auctionPivotPrice;
                  }
              
                  struct BiddingParameters {
                      uint256 minimumBid;
                      uint256 remainingCurrentSets;
                      uint256[] combinedCurrentUnits;
                      uint256[] combinedNextSetUnits;
                      address[] combinedTokenArray;
                  }
              }
              
              // File: contracts/core/interfaces/IRebalancingSetToken.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title IRebalancingSetToken
               * @author Set Protocol
               *
               * The IRebalancingSetToken interface provides a light-weight, structured way to interact with the
               * RebalancingSetToken contract from another contract.
               */
              
              interface IRebalancingSetToken {
              
                  /*
                   * Get the auction library contract used for the current rebalance
                   *
                   * @return address    Address of auction library used in the upcoming auction
                   */
                  function auctionLibrary()
                      external
                      view
                      returns (address);
              
                  /*
                   * Get totalSupply of Rebalancing Set
                   *
                   * @return  totalSupply
                   */
                  function totalSupply()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get proposalTimeStamp of Rebalancing Set
                   *
                   * @return  proposalTimeStamp
                   */
                  function proposalStartTime()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get lastRebalanceTimestamp of Rebalancing Set
                   *
                   * @return  lastRebalanceTimestamp
                   */
                  function lastRebalanceTimestamp()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get rebalanceInterval of Rebalancing Set
                   *
                   * @return  rebalanceInterval
                   */
                  function rebalanceInterval()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get rebalanceState of Rebalancing Set
                   *
                   * @return RebalancingLibrary.State    Current rebalance state of the RebalancingSetToken
                   */
                  function rebalanceState()
                      external
                      view
                      returns (RebalancingLibrary.State);
              
                  /*
                   * Get the starting amount of current SetToken for the current auction
                   *
                   * @return  rebalanceState
                   */
                  function startingCurrentSetAmount()
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Gets the balance of the specified address.
                   *
                   * @param owner      The address to query the balance of.
                   * @return           A uint256 representing the amount owned by the passed address.
                   */
                  function balanceOf(
                      address owner
                  )
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Function used to set the terms of the next rebalance and start the proposal period
                   *
                   * @param _nextSet                      The Set to rebalance into
                   * @param _auctionLibrary               The library used to calculate the Dutch Auction price
                   * @param _auctionTimeToPivot           The amount of time for the auction to go ffrom start to pivot price
                   * @param _auctionStartPrice            The price to start the auction at
                   * @param _auctionPivotPrice            The price at which the price curve switches from linear to exponential
                   */
                  function propose(
                      address _nextSet,
                      address _auctionLibrary,
                      uint256 _auctionTimeToPivot,
                      uint256 _auctionStartPrice,
                      uint256 _auctionPivotPrice
                  )
                      external;
              
                  /*
                   * Get natural unit of Set
                   *
                   * @return  uint256       Natural unit of Set
                   */
                  function naturalUnit()
                      external
                      view
                      returns (uint256);
              
                  /**
                   * Returns the address of the current base SetToken with the current allocation
                   *
                   * @return           A address representing the base SetToken
                   */
                  function currentSet()
                      external
                      view
                      returns (address);
              
                  /**
                   * Returns the address of the next base SetToken with the post auction allocation
                   *
                   * @return  address    Address representing the base SetToken
                   */
                  function nextSet()
                      external
                      view
                      returns (address);
              
                  /*
                   * Get the unit shares of the rebalancing Set
                   *
                   * @return  unitShares       Unit Shares of the base Set
                   */
                  function unitShares()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Burn set token for given address.
                   * Can only be called by authorized contracts.
                   *
                   * @param  _from        The address of the redeeming account
                   * @param  _quantity    The number of sets to burn from redeemer
                   */
                  function burn(
                      address _from,
                      uint256 _quantity
                  )
                      external;
              
                  /*
                   * Place bid during rebalance auction. Can only be called by Core.
                   *
                   * @param _quantity                 The amount of currentSet to be rebalanced
                   * @return combinedTokenArray       Array of token addresses invovled in rebalancing
                   * @return inflowUnitArray          Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray         Array of amount of tokens taken out of system in bid
                   */
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      returns (address[] memory, uint256[] memory, uint256[] memory);
              
                  /*
                   * Get combinedTokenArray of Rebalancing Set
                   *
                   * @return  combinedTokenArray
                   */
                  function getCombinedTokenArrayLength()
                      external
                      view
                      returns (uint256);
              
                  /*
                   * Get combinedTokenArray of Rebalancing Set
                   *
                   * @return  combinedTokenArray
                   */
                  function getCombinedTokenArray()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get failedAuctionWithdrawComponents of Rebalancing Set
                   *
                   * @return  failedAuctionWithdrawComponents
                   */
                  function getFailedAuctionWithdrawComponents()
                      external
                      view
                      returns (address[] memory);
              
                  /*
                   * Get auctionPriceParameters for current auction
                   *
                   * @return uint256[4]    AuctionPriceParameters for current rebalance auction
                   */
                  function getAuctionPriceParameters()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Get biddingParameters for current auction
                   *
                   * @return uint256[2]    BiddingParameters for current rebalance auction
                   */
                  function getBiddingParameters()
                      external
                      view
                      returns (uint256[] memory);
              
                  /*
                   * Get token inflows and outflows required for bid. Also the amount of Rebalancing
                   * Sets that would be generated.
                   *
                   * @param _quantity               The amount of currentSet to be rebalanced
                   * @return inflowUnitArray        Array of amount of tokens inserted into system in bid
                   * @return outflowUnitArray       Array of amount of tokens taken out of system in bid
                   */
                  function getBidPrice(
                      uint256 _quantity
                  )
                      external
                      view
                      returns (uint256[] memory, uint256[] memory);
              
              }
              
              // File: contracts/core/lib/Rebalance.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              /**
               * @title Rebalance
               * @author Set Protocol
               *
               * Types and functions for Rebalance-related data.
               */
              library Rebalance {
              
                  struct TokenFlow {
                      address[] addresses;
                      uint256[] inflow;
                      uint256[] outflow;
                  }
              
                  function composeTokenFlow(
                      address[] memory _addresses,
                      uint256[] memory _inflow,
                      uint256[] memory _outflow
                  )
                      internal
                      pure
                      returns(TokenFlow memory)
                  {
                      return TokenFlow({addresses: _addresses, inflow: _inflow, outflow: _outflow });
                  }
              
                  function decomposeTokenFlow(TokenFlow memory _tokenFlow)
                      internal
                      pure
                      returns (address[] memory, uint256[] memory, uint256[] memory)
                  {
                      return (_tokenFlow.addresses, _tokenFlow.inflow, _tokenFlow.outflow);
                  }
              
                  function decomposeTokenFlowToBidPrice(TokenFlow memory _tokenFlow)
                      internal
                      pure
                      returns (uint256[] memory, uint256[] memory)
                  {
                      return (_tokenFlow.inflow, _tokenFlow.outflow);
                  }
              
                  /**
                   * Get token flows array of addresses, inflows and outflows
                   *
                   * @param    _rebalancingSetToken   The rebalancing Set Token instance
                   * @param    _quantity              The amount of currentSet to be rebalanced
                   * @return   combinedTokenArray     Array of token addresses
                   * @return   inflowArray            Array of amount of tokens inserted into system in bid
                   * @return   outflowArray           Array of amount of tokens returned from system in bid
                   */
                  function getTokenFlows(
                      IRebalancingSetToken _rebalancingSetToken,
                      uint256 _quantity
                  )
                      internal
                      view
                      returns (address[] memory, uint256[] memory, uint256[] memory)
                  {
                      // Get token addresses
                      address[] memory combinedTokenArray = _rebalancingSetToken.getCombinedTokenArray();
              
                      // Get inflow and outflow arrays for the given bid quantity
                      (
                          uint256[] memory inflowArray,
                          uint256[] memory outflowArray
                      ) = _rebalancingSetToken.getBidPrice(_quantity);
              
                      return (combinedTokenArray, inflowArray, outflowArray);
                  }
              }
              
              // File: contracts/core/interfaces/ILiquidator.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              /**
               * @title ILiquidator
               * @author Set Protocol
               *
               */
              interface ILiquidator {
              
                  /* ============ External Functions ============ */
              
                  function startRebalance(
                      ISetToken _currentSet,
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity,
                      bytes calldata _liquidatorData
                  )
                      external;
              
                  function getBidPrice(
                      address _set,
                      uint256 _quantity
                  )
                      external
                      view
                      returns (Rebalance.TokenFlow memory);
              
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      returns (Rebalance.TokenFlow memory);
              
              
                  function settleRebalance()
                      external;
              
                  function endFailedRebalance() external;
              
                  // ----------------------------------------------------------------------
                  // Auction Price
                  // ----------------------------------------------------------------------
              
                  function auctionPriceParameters(address _set)
                      external
                      view
                      returns (RebalancingLibrary.AuctionPriceParameters memory);
              
                  // ----------------------------------------------------------------------
                  // Auction
                  // ----------------------------------------------------------------------
              
                  function hasRebalanceFailed(address _set) external view returns (bool);
                  function minimumBid(address _set) external view returns (uint256);
                  function startingCurrentSets(address _set) external view returns (uint256);
                  function remainingCurrentSets(address _set) external view returns (uint256);
                  function getCombinedCurrentSetUnits(address _set) external view returns (uint256[] memory);
                  function getCombinedNextSetUnits(address _set) external view returns (uint256[] memory);
                  function getCombinedTokenArray(address _set) external view returns (address[] memory);
              }
              
              // File: contracts/core/interfaces/IOracleWhiteList.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              /**
               * @title IOracleWhiteList
               * @author Set Protocol
               *
               * The IWhiteList interface exposes the whitelist mapping to check components
               */
              interface IOracleWhiteList {
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Returns oracle of passed token address (not in array form)
                   *
                   * @param  _tokenAddress       Address to check
                   * @return bool                Whether passed in address is whitelisted
                   */
                  function oracleWhiteList(
                      address _tokenAddress
                  )
                      external
                      view
                      returns (address);
              
                  /**
                   * Verifies an array of token addresses against the whitelist
                   *
                   * @param  _addresses    Array of addresses to verify
                   * @return bool          Whether all addresses in the list are whitelsited
                   */
                  function areValidAddresses(
                      address[] calldata _addresses
                  )
                      external
                      view
                      returns (bool);
              
                  /**
                   * Return array of oracle addresses based on passed in token addresses
                   *
                   * @param  _tokenAddresses    Array of token addresses to get oracle addresses for
                   * @return address[]          Array of oracle addresses
                   */
                  function getOracleAddressesByToken(
                      address[] calldata _tokenAddresses
                  )
                      external
                      view
                      returns (address[] memory);
              
                  function getOracleAddressByToken(
                      address _token
                  )
                      external
                      view
                      returns (address);
              }
              
              // File: openzeppelin-solidity/contracts/math/Math.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title Math
               * @dev Assorted math operations
               */
              library Math {
                  /**
                   * @dev Returns the largest of two numbers.
                   */
                  function max(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a >= b ? a : b;
                  }
              
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a < b ? a : b;
                  }
              
                  /**
                   * @dev Calculates the average of two numbers. Since these are integers,
                   * averages of an even and odd number cannot be represented, and will be
                   * rounded down.
                   */
                  function average(uint256 a, uint256 b) internal pure returns (uint256) {
                      // (a + b) / 2 can overflow, so we distribute
                      return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
                  }
              }
              
              // File: set-protocol-strategies/contracts/meta-oracles/interfaces/IOracle.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              /**
               * @title IOracle
               * @author Set Protocol
               *
               * Interface for operating with any external Oracle that returns uint256 or
               * an adapting contract that converts oracle output to uint256
               */
              interface IOracle {
              
                  /**
                   * Returns the queried data from an oracle returning uint256
                   *
                   * @return  Current price of asset represented in uint256
                   */
                  function read()
                      external
                      view
                      returns (uint256);
              }
              
              // File: contracts/lib/AddressArrayUtils.sol
              
              // Pulled in from Cryptofin Solidity package in order to control Solidity compiler version
              // https://github.com/cryptofinlabs/cryptofin-solidity/blob/master/contracts/array-utils/AddressArrayUtils.sol
              
              pragma solidity 0.5.7;
              
              
              library AddressArrayUtils {
              
                  /**
                   * Finds the index of the first occurrence of the given element.
                   * @param A The input array to search
                   * @param a The value to find
                   * @return Returns (index and isIn) for the first occurrence starting from index 0
                   */
                  function indexOf(address[] memory A, address a) internal pure returns (uint256, bool) {
                      uint256 length = A.length;
                      for (uint256 i = 0; i < length; i++) {
                          if (A[i] == a) {
                              return (i, true);
                          }
                      }
                      return (0, false);
                  }
              
                  /**
                  * Returns true if the value is present in the list. Uses indexOf internally.
                  * @param A The input array to search
                  * @param a The value to find
                  * @return Returns isIn for the first occurrence starting from index 0
                  */
                  function contains(address[] memory A, address a) internal pure returns (bool) {
                      bool isIn;
                      (, isIn) = indexOf(A, a);
                      return isIn;
                  }
              
                  /**
                   * Returns the combination of the two arrays
                   * @param A The first array
                   * @param B The second array
                   * @return Returns A extended by B
                   */
                  function extend(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 aLength = A.length;
                      uint256 bLength = B.length;
                      address[] memory newAddresses = new address[](aLength + bLength);
                      for (uint256 i = 0; i < aLength; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = 0; j < bLength; j++) {
                          newAddresses[aLength + j] = B[j];
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the array with a appended to A.
                   * @param A The first array
                   * @param a The value to append
                   * @return Returns A appended by a
                   */
                  function append(address[] memory A, address a) internal pure returns (address[] memory) {
                      address[] memory newAddresses = new address[](A.length + 1);
                      for (uint256 i = 0; i < A.length; i++) {
                          newAddresses[i] = A[i];
                      }
                      newAddresses[A.length] = a;
                      return newAddresses;
                  }
              
                  /**
                   * Returns the intersection of two arrays. Arrays are treated as collections, so duplicates are kept.
                   * @param A The first array
                   * @param B The second array
                   * @return The intersection of the two arrays
                   */
                  function intersect(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 newLength = 0;
                      for (uint256 i = 0; i < length; i++) {
                          if (contains(B, A[i])) {
                              includeMap[i] = true;
                              newLength++;
                          }
                      }
                      address[] memory newAddresses = new address[](newLength);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                   * Returns the union of the two arrays. Order is not guaranteed.
                   * @param A The first array
                   * @param B The second array
                   * @return The union of the two arrays
                   */
                  function union(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      address[] memory leftDifference = difference(A, B);
                      address[] memory rightDifference = difference(B, A);
                      address[] memory intersection = intersect(A, B);
                      return extend(leftDifference, extend(intersection, rightDifference));
                  }
              
                  /**
                   * Computes the difference of two arrays. Assumes there are no duplicates.
                   * @param A The first array
                   * @param B The second array
                   * @return The difference of the two arrays
                   */
                  function difference(address[] memory A, address[] memory B) internal pure returns (address[] memory) {
                      uint256 length = A.length;
                      bool[] memory includeMap = new bool[](length);
                      uint256 count = 0;
                      // First count the new length because can't push for in-memory arrays
                      for (uint256 i = 0; i < length; i++) {
                          address e = A[i];
                          if (!contains(B, e)) {
                              includeMap[i] = true;
                              count++;
                          }
                      }
                      address[] memory newAddresses = new address[](count);
                      uint256 j = 0;
                      for (uint256 k = 0; k < length; k++) {
                          if (includeMap[k]) {
                              newAddresses[j] = A[k];
                              j++;
                          }
                      }
                      return newAddresses;
                  }
              
                  /**
                  * Removes specified index from array
                  * Resulting ordering is not guaranteed
                  * @return Returns the new array and the removed entry
                  */
                  function pop(address[] memory A, uint256 index)
                      internal
                      pure
                      returns (address[] memory, address)
                  {
                      uint256 length = A.length;
                      address[] memory newAddresses = new address[](length - 1);
                      for (uint256 i = 0; i < index; i++) {
                          newAddresses[i] = A[i];
                      }
                      for (uint256 j = index + 1; j < length; j++) {
                          newAddresses[j - 1] = A[j];
                      }
                      return (newAddresses, A[index]);
                  }
              
                  /**
                   * @return Returns the new array
                   */
                  function remove(address[] memory A, address a)
                      internal
                      pure
                      returns (address[] memory)
                  {
                      (uint256 index, bool isIn) = indexOf(A, a);
                      if (!isIn) {
                          revert();
                      } else {
                          (address[] memory _A,) = pop(A, index);
                          return _A;
                      }
                  }
              
                  /**
                   * Returns whether or not there's a duplicate. Runs in O(n^2).
                   * @param A Array to search
                   * @return Returns true if duplicate, false otherwise
                   */
                  function hasDuplicate(address[] memory A) internal pure returns (bool) {
                      if (A.length == 0) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length - 1; i++) {
                          for (uint256 j = i + 1; j < A.length; j++) {
                              if (A[i] == A[j]) {
                                  return true;
                              }
                          }
                      }
                      return false;
                  }
              
                  /**
                   * Returns whether the two arrays are equal.
                   * @param A The first array
                   * @param B The second array
                   * @return True is the arrays are equal, false if not.
                   */
                  function isEqual(address[] memory A, address[] memory B) internal pure returns (bool) {
                      if (A.length != B.length) {
                          return false;
                      }
                      for (uint256 i = 0; i < A.length; i++) {
                          if (A[i] != B[i]) {
                              return false;
                          }
                      }
                      return true;
                  }
              }
              
              // File: contracts/core/lib/SetMath.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              /**
               * @title SetMath
               * @author Set Protocol
               */
              library SetMath {
                  using SafeMath for uint256;
              
              
                  /**
                   * Converts SetToken quantity to component quantity
                   */
                  function setToComponent(
                      uint256 _setQuantity,
                      uint256 _componentUnit,
                      uint256 _naturalUnit
                  )
                      internal
                      pure
                      returns(uint256)
                  {
                      return _setQuantity.mul(_componentUnit).div(_naturalUnit);
                  }
              
                  /**
                   * Converts component quantity to Set quantity
                   */
                  function componentToSet(
                      uint256 _componentQuantity,
                      uint256 _componentUnit,
                      uint256 _naturalUnit
                  )
                      internal
                      pure
                      returns(uint256)
                  {
                      return _componentQuantity.mul(_naturalUnit).div(_componentUnit);
                  }
              }
              
              // File: contracts/core/liquidators/impl/Auction.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              
              /**
               * @title Auction
               * @author Set Protocol
               *
               * Contract containing utility functions for liquidators that use auctions processes. Contains
               * helper functions to value collateral SetTokens and determine parameters used in bidding
               * processes. Meant to be inherited.
               */
              contract Auction {
                  using SafeMath for uint256;
                  using AddressArrayUtils for address[];
              
                  /* ============ Structs ============ */
                  struct Setup {
                      uint256 maxNaturalUnit;
                      uint256 minimumBid;
                      uint256 startTime;
                      uint256 startingCurrentSets;
                      uint256 remainingCurrentSets;
                      address[] combinedTokenArray;
                      uint256[] combinedCurrentSetUnits;
                      uint256[] combinedNextSetUnits;
                  }
              
                  /* ============ Structs ============ */
                  uint256 constant private CURVE_DENOMINATOR = 10 ** 18;
              
                  /* ============ Auction Struct Methods ============ */
              
                  /*
                   * Sets the Auction Setup struct variables.
                   *
                   * @param _auction                      Auction Setup object
                   * @param _currentSet                   The Set to rebalance from
                   * @param _nextSet                      The Set to rebalance to
                   * @param _startingCurrentSetQuantity   Quantity of currentSet to rebalance
                   */
                  function initializeAuction(
                      Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity
                  )
                      internal
                  {
                      _auction.maxNaturalUnit = Math.max(
                          _currentSet.naturalUnit(),
                          _nextSet.naturalUnit()
                      );
              
                      _auction.startingCurrentSets = _startingCurrentSetQuantity;
                      _auction.remainingCurrentSets = _startingCurrentSetQuantity;
                      _auction.startTime = block.timestamp;
                      _auction.combinedTokenArray = getCombinedTokenArray(_currentSet, _nextSet);
                      _auction.combinedCurrentSetUnits = calculateCombinedUnitArray(_auction, _currentSet);
                      _auction.combinedNextSetUnits = calculateCombinedUnitArray(_auction, _nextSet);
                  }
              
                  function reduceRemainingCurrentSets(Setup storage _auction, uint256 _quantity) internal {
                      _auction.remainingCurrentSets = _auction.remainingCurrentSets.sub(_quantity);
                  }
              
                  /*
                   * Validate bid is a multiple of minimum bid and that amount is less than remaining.
                   */
                  function validateBidQuantity(Setup storage _auction, uint256 _quantity) internal view {
                      require(
                          _quantity.mod(_auction.minimumBid) == 0,
                          "Auction.validateBidQuantity: Must bid multiple of minimum bid"
                      );
              
                      require(
                          _quantity <= _auction.remainingCurrentSets,
                          "Auction.validateBidQuantity: Bid exceeds remaining current sets"
                      );
                  }
              
                  /*
                   * Asserts whether the auction has been completed, which is when all currentSets have been
                   * rebalanced.
                   */
                  function validateAuctionCompletion(Setup storage _auction) internal view {
                      require(
                          !hasBiddableQuantity(_auction),
                          "Auction.settleRebalance: Rebalance not completed"
                      );
                  }
              
                  /**
                   * Returns whether the remainingSets is still a quantity equal or greater than the minimum bid
                   */
                  function hasBiddableQuantity(Setup storage _auction) internal view returns(bool) {
                      return _auction.remainingCurrentSets >= _auction.minimumBid;
                  }
              
                  /**
                   * Returns whether the auction is active
                   */
                  function isAuctionActive(Setup storage _auction) internal view returns(bool) {
                      return _auction.startTime > 0;
                  }
              
                  /*
                   * Calculates TokenFlows
                   *
                   * @param _auction              Auction Setup object
                   * @param _quantity             Amount of currentSets bidder is seeking to rebalance
                   * @param _price                Value representing the auction numeartor
                   */
                  function calculateTokenFlow(
                      Setup storage _auction,
                      uint256 _quantity,
                      uint256 _price
                  )
                      internal
                      view
                      returns (Rebalance.TokenFlow memory)
                  {
                      // Normalized quantity amount
                      uint256 unitsMultiplier = _quantity.div(_auction.maxNaturalUnit);
              
                      address[] memory memCombinedTokenArray = _auction.combinedTokenArray;
              
                      uint256 combinedTokenCount = memCombinedTokenArray.length;
                      uint256[] memory inflowUnitArray = new uint256[](combinedTokenCount);
                      uint256[] memory outflowUnitArray = new uint256[](combinedTokenCount);
              
                      // Cycle through each token in combinedTokenArray, calculate inflow/outflow and store
                      // result in array
                      for (uint256 i = 0; i < combinedTokenCount; i++) {
                          (
                              inflowUnitArray[i],
                              outflowUnitArray[i]
                          ) = calculateInflowOutflow(
                              _auction.combinedCurrentSetUnits[i],
                              _auction.combinedNextSetUnits[i],
                              unitsMultiplier,
                              _price
                          );
                      }
              
                      return Rebalance.composeTokenFlow(memCombinedTokenArray, inflowUnitArray, outflowUnitArray);
                  }
              
                  /**
                   * Computes the union of the currentSet and nextSet components
                   *
                   * @param _currentSet               The Set to rebalance from
                   * @param _nextSet                  The Set to rebalance to
                   * @return                          Aggregated components array
                   */
                  function getCombinedTokenArray(
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns(address[] memory)
                  {
                      address[] memory currentSetComponents = _currentSet.getComponents();
                      address[] memory nextSetComponents = _nextSet.getComponents();
                      return currentSetComponents.union(nextSetComponents);
                  }
              
                  /*
                   * Calculates token inflow/outflow for single component in combinedTokenArray
                   *
                   * @param _currentUnit          Amount of token i in currentSet per minimum bid amount
                   * @param _nextSetUnit          Amount of token i in nextSet per minimum bid amount
                   * @param _unitsMultiplier      Bid amount normalized to number of minimum bid amounts
                   * @param _price                Auction price numerator with 10 ** 18 as denominator
                   * @return inflowUnit           Amount of token i transferred into the system
                   * @return outflowUnit          Amount of token i transferred to the bidder
                   */
                  function calculateInflowOutflow(
                      uint256 _currentUnit,
                      uint256 _nextSetUnit,
                      uint256 _unitsMultiplier,
                      uint256 _price
                  )
                      internal
                      pure
                      returns (uint256, uint256)
                  {
                      /*
                       * Below is a mathematically simplified formula for calculating token inflows and
                       * outflows, the following is it's derivation:
                       * token_flow = (bidQuantity/price)*(nextUnit - price*currentUnit)
                       *
                       * Where,
                       * 1) price = (priceNumerator/priceDivisor),
                       * 2) nextUnit and currentUnit are the amount of component i needed for a
                       * standardAmount of sets to be rebalanced where one standardAmount =
                       * max(natural unit nextSet, natural unit currentSet), and
                       * 3) bidQuantity is a normalized amount in terms of the standardAmount used
                       * to calculate nextUnit and currentUnit. This is represented by the unitsMultiplier
                       * variable.
                       *
                       * Given these definitions we can derive the below formula as follows:
                       * token_flow = (unitsMultiplier/(priceNumerator/priceDivisor))*
                       * (nextUnit - (priceNumerator/priceDivisor)*currentUnit)
                       *
                       * We can then multiply this equation by (priceDivisor/priceDivisor)
                       * which simplifies the above equation to:
                       *
                       * (unitsMultiplier/priceNumerator)* (nextUnit*priceDivisor - currentUnit*priceNumerator)
                       *
                       * This is the equation seen below, but since unsigned integers are used we must check to see if
                       * nextUnit*priceDivisor > currentUnit*priceNumerator, otherwise those two terms must be
                       * flipped in the equation.
                       */
                      uint256 inflowUnit;
                      uint256 outflowUnit;
              
                      // Use if statement to check if token inflow or outflow
                      if (_nextSetUnit.mul(CURVE_DENOMINATOR) > _currentUnit.mul(_price)) {
                          // Calculate inflow amount
                          inflowUnit = _unitsMultiplier.mul(
                              _nextSetUnit.mul(CURVE_DENOMINATOR).sub(_currentUnit.mul(_price))
                          ).div(_price);
              
                          // Set outflow amount to 0 for component i, since tokens need to be injected in rebalance
                          outflowUnit = 0;
                      } else {
                          // Calculate outflow amount
                          outflowUnit = _unitsMultiplier.mul(
                              _currentUnit.mul(_price).sub(_nextSetUnit.mul(CURVE_DENOMINATOR))
                          ).div(_price);
              
                          // Set inflow amount to 0 for component i, since tokens need to be returned in rebalance
                          inflowUnit = 0;
                      }
              
                      return (inflowUnit, outflowUnit);
                  }
              
                  /* ============ Token Array Creation Helpers ============ */
              
                  /**
                   * Create uint256 arrays that represents all components in currentSet and nextSet.
                   * Calcualate unit difference between both sets relative to the largest natural
                   * unit of the two sets.
                   *
                   * @param _auction           Auction Setup object
                   * @param _set               The Set to generate units for
                   * @return combinedUnits
                   */
                  function calculateCombinedUnitArray(
                      Setup storage _auction,
                      ISetToken _set
                  )
                      internal
                      view
                      returns (uint256[] memory)
                  {
                      address[] memory combinedTokenArray = _auction.combinedTokenArray;
                      uint256[] memory combinedUnits = new uint256[](combinedTokenArray.length);
                      for (uint256 i = 0; i < combinedTokenArray.length; i++) {
                          combinedUnits[i] = calculateCombinedUnit(
                              _set,
                              _auction.maxNaturalUnit,
                              combinedTokenArray[i]
                          );
                      }
              
                      return combinedUnits;
                  }
              
                  /**
                   * Calculations the unit amount of Token to include in the the combined Set units.
                   *
                   * @param _setToken                 Information on the SetToken
                   * @param _maxNaturalUnit           Max natural unit of two sets in rebalance
                   * @param _component                Current component in iteration
                   * @return                          Unit inflow/outflow
                   */
                  function calculateCombinedUnit(
                      ISetToken _setToken,
                      uint256 _maxNaturalUnit,
                      address _component
                  )
                      private
                      view
                      returns (uint256)
                  {
                      // Check if component in arrays and get index if it is
                      (
                          uint256 indexCurrent,
                          bool isComponent
                      ) = _setToken.getComponents().indexOf(_component);
              
                      // Compute unit amounts of token in Set
                      if (isComponent) {
                          return calculateTransferValue(
                              _setToken.getUnits()[indexCurrent],
                              _setToken.naturalUnit(),
                              _maxNaturalUnit
                          );
                      }
              
                      return 0;
                  }
              
                 /**
                   * Function to calculate the transfer value of a component given a standardized bid amount
                   * (minimumBid/priceDivisor)
                   *
                   * @param   _unit               Units of the component token
                   * @param   _naturalUnit        Natural unit of the Set token
                   * @param   _maxNaturalUnit     Max natural unit of two sets in rebalance
                   * @return  uint256             Amount of tokens per standard bid amount (minimumBid/priceDivisor)
                   */
                  function calculateTransferValue(
                      uint256 _unit,
                      uint256 _naturalUnit,
                      uint256 _maxNaturalUnit
                  )
                      private
                      pure
                      returns (uint256)
                  {
                      return SetMath.setToComponent(_maxNaturalUnit, _unit, _naturalUnit);
                  }
              }
              
              // File: contracts/core/liquidators/impl/LinearAuction.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              /**
               * @title LinearAuction
               * @author Set Protocol
               *
               * Library containing utility functions for computing auction Price for a linear price auction.
               */
              contract LinearAuction is Auction {
                  using SafeMath for uint256;
              
                  /* ============ Structs ============ */
                  struct State {
                      Auction.Setup auction;
                      uint256 endTime;
                      uint256 startPrice;
                      uint256 endPrice;
                  }
              
                  /* ============ State Variables ============ */
                  uint256 public auctionPeriod; // Length in seconds of auction
              
                  /**
                   * LinearAuction constructor
                   *
                   * @param _auctionPeriod          Length of auction
                   */
                  constructor(
                      uint256 _auctionPeriod
                  )
                      public
                  {
                      auctionPeriod = _auctionPeriod;
                  }
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Populates the linear auction struct following an auction initiation.
                   *
                   * @param _linearAuction                LinearAuction State object
                   * @param _currentSet                   The Set to rebalance from
                   * @param _nextSet                      The Set to rebalance to
                   * @param _startingCurrentSetQuantity   Quantity of currentSet to rebalance
                   */
                  function initializeLinearAuction(
                      State storage _linearAuction,
                      ISetToken _currentSet,
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity
                  )
                      internal
                  {
                      initializeAuction(
                          _linearAuction.auction,
                          _currentSet,
                          _nextSet,
                          _startingCurrentSetQuantity
                      );
              
                      uint256 minimumBid = calculateMinimumBid(_linearAuction.auction, _currentSet, _nextSet);
              
                      // remainingCurrentSets must be greater than minimumBid or no bidding would be allowed
                      require(
                          _startingCurrentSetQuantity.div(minimumBid) >= 100,
                          "Auction.initializeAuction: Minimum bid must be less than or equal to 1% of collateral."
                      );
              
                      _linearAuction.auction.minimumBid = minimumBid;
              
                      _linearAuction.startPrice = calculateStartPrice(_linearAuction.auction, _currentSet, _nextSet);
                      _linearAuction.endPrice = calculateEndPrice(_linearAuction.auction, _currentSet, _nextSet);
              
                      _linearAuction.endTime = block.timestamp.add(auctionPeriod);
                  }
              
                  /* ============ Internal View Functions ============ */
              
                  /**
                   * Returns the TokenFlow based on the current price
                   */
                  function getTokenFlow(
                      State storage _linearAuction,
                      uint256 _quantity
                  )
                      internal
                      view
                      returns (Rebalance.TokenFlow memory)
                  {
                      return Auction.calculateTokenFlow(
                          _linearAuction.auction,
                          _quantity,
                          getPrice(_linearAuction)
                      );
                  }
              
                  /**
                   * Auction failed is defined the timestamp breacnhing the auction end time and
                   * the auction not being complete
                   */
                  function hasAuctionFailed(State storage _linearAuction) internal view returns(bool) {
                      bool endTimeExceeded = block.timestamp >= _linearAuction.endTime;
                      bool setsNotAuctioned = hasBiddableQuantity(_linearAuction.auction);
              
                      return (endTimeExceeded && setsNotAuctioned);
                  }
              
                  /**
                   * Returns the price based on the current timestamp. Returns the endPrice
                   * if time has exceeded the auction period
                   *
                   * @param _linearAuction            Linear Auction State object
                   * @return price                    uint representing the current price
                   */
                  function getPrice(State storage _linearAuction) internal view returns (uint256) {
                      uint256 elapsed = block.timestamp.sub(_linearAuction.auction.startTime);
              
                      // If current time has elapsed
                      if (elapsed >= auctionPeriod) {
                          return _linearAuction.endPrice;
                      } else {
                          uint256 range = _linearAuction.endPrice.sub(_linearAuction.startPrice);
                          uint256 elapsedPrice = elapsed.mul(range).div(auctionPeriod);
              
                          return _linearAuction.startPrice.add(elapsedPrice);
                      }
                  }
              
                  /**
                   * Abstract function that must be implemented.
                   * Calculate the minimumBid allowed for the rebalance.
                   *
                   * @param _auction            Auction object
                   * @param _currentSet         The Set to rebalance from
                   * @param _nextSet            The Set to rebalance to
                   * @return                    Minimum bid amount
                   */
                  function calculateMinimumBid(
                      Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns (uint256);
              
                  /**
                   * Abstract function that must be implemented.
                   * Calculates the linear auction start price
                   */
                  function calculateStartPrice(
                      Auction.Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns(uint256);
              
                  /**
                   * Abstract function that must be implemented.
                   * Calculates the linear auction end price
                   */
                  function calculateEndPrice(
                      Auction.Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns(uint256);
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              pragma solidity ^0.5.2;
              
              /**
               * @title ERC20 interface
               * @dev see https://eips.ethereum.org/EIPS/eip-20
               */
              interface IERC20 {
                  function transfer(address to, uint256 value) external returns (bool);
              
                  function approve(address spender, uint256 value) external returns (bool);
              
                  function transferFrom(address from, address to, uint256 value) external returns (bool);
              
                  function totalSupply() external view returns (uint256);
              
                  function balanceOf(address who) external view returns (uint256);
              
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol
              
              pragma solidity ^0.5.2;
              
              
              /**
               * @title ERC20Detailed token
               * @dev The decimals are only for visualization purposes.
               * All the operations are done using the smallest and indivisible token unit,
               * just as on Ethereum all the operations are done in wei.
               */
              contract ERC20Detailed is IERC20 {
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
              
                  constructor (string memory name, string memory symbol, uint8 decimals) public {
                      _name = name;
                      _symbol = symbol;
                      _decimals = decimals;
                  }
              
                  /**
                   * @return the name of the token.
                   */
                  function name() public view returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @return the symbol of the token.
                   */
                  function symbol() public view returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @return the number of decimals of the token.
                   */
                  function decimals() public view returns (uint8) {
                      return _decimals;
                  }
              }
              
              // File: contracts/lib/CommonMath.sol
              
              /*
                  Copyright 2018 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              library CommonMath {
                  using SafeMath for uint256;
              
                  uint256 public constant SCALE_FACTOR = 10 ** 18;
                  uint256 public constant MAX_UINT_256 = 2 ** 256 - 1;
              
                  /**
                   * Returns scale factor equal to 10 ** 18
                   *
                   * @return  10 ** 18
                   */
                  function scaleFactor()
                      internal
                      pure
                      returns (uint256)
                  {
                      return SCALE_FACTOR;
                  }
              
                  /**
                   * Calculates and returns the maximum value for a uint256
                   *
                   * @return  The maximum value for uint256
                   */
                  function maxUInt256()
                      internal
                      pure
                      returns (uint256)
                  {
                      return MAX_UINT_256;
                  }
              
                  /**
                   * Increases a value by the scale factor to allow for additional precision
                   * during mathematical operations
                   */
                  function scale(
                      uint256 a
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      return a.mul(SCALE_FACTOR);
                  }
              
                  /**
                   * Divides a value by the scale factor to allow for additional precision
                   * during mathematical operations
                  */
                  function deScale(
                      uint256 a
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      return a.div(SCALE_FACTOR);
                  }
              
                  /**
                  * @dev Performs the power on a specified value, reverts on overflow.
                  */
                  function safePower(
                      uint256 a,
                      uint256 pow
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      require(a > 0);
              
                      uint256 result = 1;
                      for (uint256 i = 0; i < pow; i++){
                          uint256 previousResult = result;
              
                          // Using safemath multiplication prevents overflows
                          result = previousResult.mul(a);
                      }
              
                      return result;
                  }
              
                  /**
                  * @dev Performs division where if there is a modulo, the value is rounded up
                  */
                  function divCeil(uint256 a, uint256 b)
                      internal
                      pure
                      returns(uint256)
                  {
                      return a.mod(b) > 0 ? a.div(b).add(1) : a.div(b);
                  }
              
                  /**
                   * Checks for rounding errors and returns value of potential partial amounts of a principal
                   *
                   * @param  _principal       Number fractional amount is derived from
                   * @param  _numerator       Numerator of fraction
                   * @param  _denominator     Denominator of fraction
                   * @return uint256          Fractional amount of principal calculated
                   */
                  function getPartialAmount(
                      uint256 _principal,
                      uint256 _numerator,
                      uint256 _denominator
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Get remainder of partial amount (if 0 not a partial amount)
                      uint256 remainder = mulmod(_principal, _numerator, _denominator);
              
                      // Return if not a partial amount
                      if (remainder == 0) {
                          return _principal.mul(_numerator).div(_denominator);
                      }
              
                      // Calculate error percentage
                      uint256 errPercentageTimes1000000 = remainder.mul(1000000).div(_numerator.mul(_principal));
              
                      // Require error percentage is less than 0.1%.
                      require(
                          errPercentageTimes1000000 < 1000,
                          "CommonMath.getPartialAmount: Rounding error exceeds bounds"
                      );
              
                      return _principal.mul(_numerator).div(_denominator);
                  }
              
                  /*
                   * Gets the rounded up log10 of passed value
                   *
                   * @param  _value         Value to calculate ceil(log()) on
                   * @return uint256        Output value
                   */
                  function ceilLog10(
                      uint256 _value
                  )
                      internal
                      pure
                      returns (uint256)
                  {
                      // Make sure passed value is greater than 0
                      require (
                          _value > 0,
                          "CommonMath.ceilLog10: Value must be greater than zero."
                      );
              
                      // Since log10(1) = 0, if _value = 1 return 0
                      if (_value == 1) return 0;
              
                      // Calcualte ceil(log10())
                      uint256 x = _value - 1;
              
                      uint256 result = 0;
              
                      if (x >= 10 ** 64) {
                          x /= 10 ** 64;
                          result += 64;
                      }
                      if (x >= 10 ** 32) {
                          x /= 10 ** 32;
                          result += 32;
                      }
                      if (x >= 10 ** 16) {
                          x /= 10 ** 16;
                          result += 16;
                      }
                      if (x >= 10 ** 8) {
                          x /= 10 ** 8;
                          result += 8;
                      }
                      if (x >= 10 ** 4) {
                          x /= 10 ** 4;
                          result += 4;
                      }
                      if (x >= 100) {
                          x /= 100;
                          result += 2;
                      }
                      if (x >= 10) {
                          result += 1;
                      }
              
                      return result + 1;
                  }
              }
              
              // File: contracts/core/liquidators/impl/TwoAssetPriceBoundedLinearAuction.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              
              
              
              
              
              
              
              
              
              
              
              /**
               * @title TwoAssetPriceBoundedLinearAuction
               * @author Set Protocol
               *
               * Contract to calculate minimumBid and auction start bounds for auctions containing only
               * an asset pair.
               */
              contract TwoAssetPriceBoundedLinearAuction is LinearAuction {
                  using SafeMath for uint256;
                  using CommonMath for uint256;
              
                  /* ============ Struct ============ */
                  struct AssetInfo {
                      uint256 price;
                      uint256 fullUnit;
                  }
              
                  /* ============ Constants ============ */
                  uint256 constant private CURVE_DENOMINATOR = 10 ** 18;
                  uint256 constant private ONE = 1;
                  // Minimum token flow allowed at spot price in auction
                  uint256 constant private MIN_SPOT_TOKEN_FLOW_SCALED = 10 ** 21;
                  uint256 constant private ONE_HUNDRED = 100;
              
                  /* ============ State Variables ============ */
                  IOracleWhiteList public oracleWhiteList;
                  uint256 public rangeStart; // Percentage below FairValue to begin auction at
                  uint256 public rangeEnd;  // Percentage above FairValue to end auction at
              
                  /**
                   * TwoAssetPriceBoundedLinearAuction constructor
                   *
                   * @param _auctionPeriod          Length of auction
                   * @param _rangeStart             Percentage below FairValue to begin auction at
                   * @param _rangeEnd               Percentage above FairValue to end auction at
                   */
                  constructor(
                      IOracleWhiteList _oracleWhiteList,
                      uint256 _auctionPeriod,
                      uint256 _rangeStart,
                      uint256 _rangeEnd
                  )
                      public
                      LinearAuction(_auctionPeriod)
                  {
                      oracleWhiteList = _oracleWhiteList;
                      rangeStart = _rangeStart;
                      rangeEnd = _rangeEnd;
                  }
              
                  /* ============ Internal Functions ============ */
              
                  /**
                   * Validates that the auction only includes two components and the components are valid.
                   */
                  function validateTwoAssetPriceBoundedAuction(
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                  {
                      address[] memory combinedTokenArray = Auction.getCombinedTokenArray(_currentSet, _nextSet);
                      require(
                          combinedTokenArray.length == 2,
                          "TwoAssetPriceBoundedLinearAuction: Only two components are allowed."
                      );
              
                      require(
                          oracleWhiteList.areValidAddresses(combinedTokenArray),
                          "TwoAssetPriceBoundedLinearAuction: Passed token does not have matching oracle."
                      );
                  }
              
                  /**
                   * Calculates the minimumBid. First calculates the minimum token flow for the pair at fair value using
                   * maximum natural unit of two Sets. If that token flow is below 1000 units then calculate minimumBid
                   * as such:
                   *
                   * minimumBid = maxNaturalUnit*1000/min(tokenFlow)
                   *
                   * Else, set minimumBid equal to maxNaturalUnit. This is to ensure that around fair value there is ample
                   * granualarity in asset pair price changes and not large discontinuities.
                   *
                   * @param _auction            Auction object
                   * @param _currentSet         CurrentSet, unused in this implementation
                   * @param _nextSet            NextSet, unused in this implementation
                   */
                  function calculateMinimumBid(
                      Auction.Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns (uint256)
                  {
                      // Get full Unit amount and price for each asset
                      AssetInfo memory assetOne = getAssetInfo(_auction.combinedTokenArray[0]);
                      AssetInfo memory assetTwo = getAssetInfo(_auction.combinedTokenArray[1]);
              
                      // Calculate current spot price as assetOne/assetTwo
                      uint256 spotPrice = calculateSpotPrice(assetOne.price, assetTwo.price);
              
                      // Calculate auction price at current asset pair spot price
                      uint256 auctionFairValue = convertAssetPairPriceToAuctionPrice(
                          _auction,
                          spotPrice,
                          assetOne.fullUnit,
                          assetTwo.fullUnit
                      );
              
                      uint256 minimumBidMultiplier = 0;
                      for (uint8 i = 0; i < _auction.combinedTokenArray.length; i++) {
                          // Get token flow at fair value for asset i, using an amount equal to ONE maxNaturalUnit
                          // Hence the ONE.scale()
                          (
                              uint256 tokenInflowScaled,
                              uint256 tokenOutflowScaled
                          ) = Auction.calculateInflowOutflow(
                              _auction.combinedCurrentSetUnits[i],
                              _auction.combinedNextSetUnits[i],
                              ONE.scale(),
                              auctionFairValue
                          );
              
                          // One returned number from previous function will be zero so use max to get tokenFlow
                          uint256 tokenFlowScaled = Math.max(tokenInflowScaled, tokenOutflowScaled);
              
                          // Divide minimum spot token flow (1000 units) by token flow if more than minimumBidMultiplier
                          // update minimumBidMultiplier
                          uint256 currentMinBidMultiplier = MIN_SPOT_TOKEN_FLOW_SCALED.divCeil(tokenFlowScaled);
                          minimumBidMultiplier = currentMinBidMultiplier > minimumBidMultiplier ?
                              currentMinBidMultiplier :
                              minimumBidMultiplier;
                      }
              
                      // Multiply the minimumBidMultiplier by maxNaturalUnit to get minimumBid
                      return _auction.maxNaturalUnit.mul(minimumBidMultiplier);
                  }
              
                  /**
                   * Calculates the linear auction start price. A target asset pair (i.e. ETH/DAI) price is calculated
                   * to start the auction at, that asset pair price is then translated into the equivalent auction price.
                   *
                   * @param _auction            Auction object
                   * @param _currentSet         CurrentSet, unused in this implementation
                   * @param _nextSet            NextSet, unused in this implementation
                   */
                  function calculateStartPrice(
                      Auction.Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns(uint256)
                  {
                      // Get full Unit amount and price for each asset
                      AssetInfo memory assetOne = getAssetInfo(_auction.combinedTokenArray[0]);
                      AssetInfo memory assetTwo = getAssetInfo(_auction.combinedTokenArray[1]);
              
                      // Calculate current asset pair spot price as assetOne/assetTwo
                      uint256 spotPrice = calculateSpotPrice(assetOne.price, assetTwo.price);
              
                      // Check to see if asset pair price is increasing or decreasing as time passes
                      bool isTokenFlowIncreasing = isTokenFlowIncreasing(
                          _auction,
                          spotPrice,
                          assetOne.fullUnit,
                          assetTwo.fullUnit
                      );
              
                      // If price implied by token flows is increasing then target price we are using for lower bound
                      // is below current spot price, if flows decreasing set target price above spotPrice
                      uint256 startPairPrice;
                      if (isTokenFlowIncreasing) {
                          startPairPrice = spotPrice.mul(ONE_HUNDRED.sub(rangeStart)).div(ONE_HUNDRED);
                      } else {
                          startPairPrice = spotPrice.mul(ONE_HUNDRED.add(rangeStart)).div(ONE_HUNDRED);
                      }
              
                      // Convert start asset pair price to equivalent auction price
                      return convertAssetPairPriceToAuctionPrice(
                          _auction,
                          startPairPrice,
                          assetOne.fullUnit,
                          assetTwo.fullUnit
                      );
                  }
              
                  /**
                   * Calculates the linear auction end price. A target asset pair (i.e. ETH/DAI) price is calculated
                   * to end the auction at, that asset pair price is then translated into the equivalent auction price.
                   *
                   * @param _auction            Auction object
                   * @param _currentSet         CurrentSet, unused in this implementation
                   * @param _nextSet            NextSet, unused in this implementation
                   */
                  function calculateEndPrice(
                      Auction.Setup storage _auction,
                      ISetToken _currentSet,
                      ISetToken _nextSet
                  )
                      internal
                      view
                      returns(uint256)
                  {
                      // Get full Unit amount and price for each asset
                      AssetInfo memory assetOne = getAssetInfo(_auction.combinedTokenArray[0]);
                      AssetInfo memory assetTwo = getAssetInfo(_auction.combinedTokenArray[1]);
              
                      // Calculate current spot price as assetOne/assetTwo
                      uint256 spotPrice = calculateSpotPrice(assetOne.price, assetTwo.price);
              
                      // Check to see if asset pair price is increasing or decreasing as time passes
                      bool isTokenFlowIncreasing = isTokenFlowIncreasing(
                          _auction,
                          spotPrice,
                          assetOne.fullUnit,
                          assetTwo.fullUnit
                      );
              
                      // If price implied by token flows is increasing then target price we are using for upper bound
                      // is above current spot price, if flows decreasing set target price below spotPrice
                      uint256 endPairPrice;
                      if (isTokenFlowIncreasing) {
                          endPairPrice = spotPrice.mul(ONE_HUNDRED.add(rangeEnd)).div(ONE_HUNDRED);
                      } else {
                          endPairPrice = spotPrice.mul(ONE_HUNDRED.sub(rangeEnd)).div(ONE_HUNDRED);
                      }
              
                      // Convert end asset pair price to equivalent auction price
                      return convertAssetPairPriceToAuctionPrice(
                          _auction,
                          endPairPrice,
                          assetOne.fullUnit,
                          assetTwo.fullUnit
                      );
                  }
              
                  /* ============ Private Functions ============ */
              
                  /**
                   * Determines if asset pair price is increasing or decreasing as time passed in auction. Used to set the
                   * auction price bounds. Below a refers to any asset and subscripts c, n, d mean currentSetUnit, nextSetUnit
                   * and fullUnit amount, respectively. pP and pD refer to auction price and auction denominator. Asset pair
                   * price is defined as such:
                   *
                   * assetPrice = abs(assetTwoOutflow/assetOneOutflow)
                   *
                   * The equation for an outflow is given by (a_c/a_d)*pP - (a_n/a_d)*pD). It can be proven that the derivative
                   * of this equation is always increasing. Thus by determining the sign of the assetOneOutflow (where a negative
                   * amount signifies an inflow) it can be determined whether the asset pair price is increasing or decreasing.
                   *
                   * For example, if assetOneOutflow is negative it means that the denominator is getting smaller as time passes
                   * and thus the assetPrice is increasing during the auction.
                   *
                   * @param _auction              Auction object
                   * @param _spotPrice            Current spot price provided by asset oracles
                   * @param _assetOneFullUnit     Units in one full unit of assetOne
                   * @param _assetTwoFullUnit     Units in one full unit of assetTwo
                   */
                  function isTokenFlowIncreasing(
                      Auction.Setup storage _auction,
                      uint256 _spotPrice,
                      uint256 _assetOneFullUnit,
                      uint256 _assetTwoFullUnit
                  )
                      private
                      view
                      returns (bool)
                  {
                      // Calculate auction price at current asset pair spot price
                      uint256 auctionFairValue = convertAssetPairPriceToAuctionPrice(
                          _auction,
                          _spotPrice,
                          _assetOneFullUnit,
                          _assetTwoFullUnit
                      );
              
                      // Determine whether outflow for assetOne is positive or negative, if positive then asset pair price is
                      // increasing, else decreasing.
                      return _auction.combinedNextSetUnits[0].mul(CURVE_DENOMINATOR) >
                          _auction.combinedCurrentSetUnits[0].mul(auctionFairValue);
                  }
              
                  /**
                   * Convert an asset pair price to the equivalent auction price where a1 refers to assetOne and a2 refers to assetTwo
                   * and subscripts c, n, d mean currentSetUnit, nextSetUnit and fullUnit amount, respectively. pP and pD refer to auction
                   * price and auction denominator:
                   *
                   * assetPrice = abs(assetTwoOutflow/assetOneOutflow)
                   *
                   * assetPrice = ((a2_c/a2_d)*pP - (a2_n/a2_d)*pD) / ((a1_c/a1_d)*pP - (a1_n/a1_d)*pD)
                   *
                   * We know assetPrice so we isolate for pP:
                   *
                   * pP = pD((a2_n/a2_d)+assetPrice*(a1_n/a1_d)) / (a2_c/a2_d)+assetPrice*(a1_c/a1_d)
                   *
                   * This gives us the auction price that matches with the passed asset pair price.
                   *
                   * @param _auction              Auction object
                   * @param _targetPrice          Target asset pair price
                   * @param _assetOneFullUnit     Units in one full unit of assetOne
                   * @param _assetTwoFullUnit     Units in one full unit of assetTwo
                   */
                  function convertAssetPairPriceToAuctionPrice(
                      Auction.Setup storage _auction,
                      uint256 _targetPrice,
                      uint256 _assetOneFullUnit,
                      uint256 _assetTwoFullUnit
                  )
                      private
                      view
                      returns (uint256)
                  {
                      // Calculate the numerator for the above equation. In order to ensure no rounding down errors we distribute the auction
                      // denominator. Additionally, since the price is passed as an 18 decimal number in order to maintain consistency we
                      // have to scale the first term up accordingly
                      uint256 calcNumerator = _auction.combinedNextSetUnits[1].mul(CURVE_DENOMINATOR).scale().div(_assetTwoFullUnit).add(
                          _targetPrice.mul(_auction.combinedNextSetUnits[0]).mul(CURVE_DENOMINATOR).div(_assetOneFullUnit)
                      );
              
                      // Calculate the denominator for the above equation. As above we we have to scale the first term match the 18 decimal
                      // price. Furthermore since we are not guaranteed that targetPrice * a1_c > a1_d we have to scale the second term and
                      // thus also the first term in order to match (hence the two scale() in the first term)
                      uint256 calcDenominator = _auction.combinedCurrentSetUnits[1].scale().scale().div(_assetTwoFullUnit).add(
                         _targetPrice.mul(_auction.combinedCurrentSetUnits[0]).scale().div(_assetOneFullUnit)
                      );
              
                      // Here the scale required to account for the 18 decimal price cancels out since it was applied to both the numerator
                      // and denominator. However, there was an extra scale applied to the denominator that we need to remove, in order to
                      // do so we'll just apply another scale to the numerator before dividing since 1/(1/10 ** 18) = 10 ** 18!
                      return calcNumerator.scale().div(calcDenominator);
                  }
              
                  /**
                   * Get fullUnit amount and price of given asset.
                   *
                   * @param _asset            Address of auction to get information from
                   */
                  function getAssetInfo(address _asset) private view returns(AssetInfo memory) {
                      address assetOracle = oracleWhiteList.getOracleAddressByToken(_asset);
                      uint256 assetPrice = IOracle(assetOracle).read();
              
                      uint256 decimals = ERC20Detailed(_asset).decimals();
              
                      return AssetInfo({
                          price: assetPrice,
                          fullUnit: CommonMath.safePower(10, decimals)
                      });
                  }
              
                  /**
                   * Calculate asset pair price given two prices.
                   */
                  function calculateSpotPrice(uint256 _assetOnePrice, uint256 _assetTwoPrice) private view returns(uint256) {
                      return _assetOnePrice.scale().div(_assetTwoPrice);
                  }
              }
              
              // File: contracts/core/liquidators/LinearAuctionLiquidator.sol
              
              /*
                  Copyright 2019 Set Labs Inc.
              
                  Licensed under the Apache License, Version 2.0 (the "License");
                  you may not use this file except in compliance with the License.
                  You may obtain a copy of the License at
              
                  http://www.apache.org/licenses/LICENSE-2.0
              
                  Unless required by applicable law or agreed to in writing, software
                  distributed under the License is distributed on an "AS IS" BASIS,
                  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                  See the License for the specific language governing permissions and
                  limitations under the License.
              */
              
              pragma solidity 0.5.7;
              pragma experimental "ABIEncoderV2";
              
              
              
              
              
              
              
              
              
              
              
              
              /**
               * @title LinearAuctionLiquidator
               * @author Set Protocol
               *
               * Contract that holds all the state and functionality required for setting up, returning prices, and tearing
               * down linear auction rebalances for RebalancingSetTokens.
               */
              contract LinearAuctionLiquidator is TwoAssetPriceBoundedLinearAuction, ILiquidator {
                  using SafeMath for uint256;
              
                  ICore public core;
                  string public name;
                  mapping(address => LinearAuction.State) public auctions;
              
                  /* ============ Modifier ============ */
                  modifier isValidSet() {
                      requireValidSet(msg.sender);
                      _;
                  }
              
                  /**
                   * LinearAuctionLiquidator constructor
                   *
                   * @param _core                   Core instance
                   * @param _oracleWhiteList        Oracle WhiteList instance
                   * @param _auctionPeriod          Length of auction
                   * @param _rangeStart             Percentage above FairValue to begin auction at
                   * @param _rangeEnd               Percentage below FairValue to end auction at
                   * @param _name                   Descriptive name of Liquidator
                   */
                  constructor(
                      ICore _core,
                      IOracleWhiteList _oracleWhiteList,
                      uint256 _auctionPeriod,
                      uint256 _rangeStart,
                      uint256 _rangeEnd,
                      string memory _name
                  )
                      public
                      TwoAssetPriceBoundedLinearAuction(
                          _oracleWhiteList,
                          _auctionPeriod,
                          _rangeStart,
                          _rangeEnd
                      )
                  {
                      core = _core;
                      name = _name;
                  }
              
                  /* ============ External Functions ============ */
              
                  /**
                   * Initiates a linear auction. Can only be called by a SetToken.
                   *
                   * @param _currentSet                   The Set to rebalance from
                   * @param _nextSet                      The Set to rebalance to
                   * @param _startingCurrentSetQuantity   The currentSet quantity to rebalance
                   * @param _liquidatorData                  Bytecode formatted data with liquidator-specific arguments
                   */
                  function startRebalance(
                      ISetToken _currentSet,
                      ISetToken _nextSet,
                      uint256 _startingCurrentSetQuantity,
                      bytes calldata _liquidatorData
                  )
                      external
                      isValidSet
                  {
                      _liquidatorData; // Pass linting
              
                      TwoAssetPriceBoundedLinearAuction.validateTwoAssetPriceBoundedAuction(
                          _currentSet,
                          _nextSet
                      );
              
                      LinearAuction.initializeLinearAuction(
                          linearAuction(msg.sender),
                          _currentSet,
                          _nextSet,
                          _startingCurrentSetQuantity
                      );
                  }
              
                  /**
                   * Reduces the remainingCurrentSet quantity and retrieves the current
                   * bid price.
                   * Can only be called by a SetToken during an active auction
                   *
                   * @param _quantity               The currentSetQuantity to rebalance
                   * @return TokenFlow              Struct with array, inflow, and outflow data
                   */
                  function placeBid(
                      uint256 _quantity
                  )
                      external
                      isValidSet
                      returns (Rebalance.TokenFlow memory)
                  {
                      Auction.validateBidQuantity(auction(msg.sender), _quantity);
              
                      Auction.reduceRemainingCurrentSets(auction(msg.sender), _quantity);
              
                      return getBidPrice(msg.sender, _quantity);
                  }
              
                  /**
                   * Retrieves the current auction price for the particular Set
                   *
                   * @param _set                    Address of the SetToken
                   * @param _quantity               The currentSetQuantity to rebalance
                   * @return TokenFlow              Struct with array, inflow, and outflow data
                   */
                  function getBidPrice(
                      address _set,
                      uint256 _quantity
                  )
                      public
                      view
                      returns (Rebalance.TokenFlow memory)
                  {
                      return LinearAuction.getTokenFlow(linearAuction(_set), _quantity);
                  }
              
                  /**
                   * Validates auction completion and clears auction state.
                   */
                  function settleRebalance() external isValidSet {
              
                      Auction.validateAuctionCompletion(auction(msg.sender));
              
                      clearAuctionState(msg.sender);
                  }
              
                  /**
                   * Clears auction state.
                   */
                  function endFailedRebalance() external isValidSet {
              
                      clearAuctionState(msg.sender);
                  }
              
                  /* ============ Getters Functions ============ */
              
                  function hasRebalanceFailed(address _set) external view returns (bool) {
                      return LinearAuction.hasAuctionFailed(linearAuction(_set));
                  }
              
                  function minimumBid(address _set) external view returns (uint256) {
                      return auction(_set).minimumBid;
                  }
              
                  function remainingCurrentSets(address _set) external view returns (uint256) {
                      return auction(_set).remainingCurrentSets;
                  }
              
                  function startingCurrentSets(address _set) external view returns (uint256) {
                      return auction(_set).startingCurrentSets;
                  }
              
                  function getCombinedTokenArray(address _set) external view returns (address[] memory) {
                      return auction(_set).combinedTokenArray;
                  }
              
                  function getCombinedCurrentSetUnits(address _set) external view returns (uint256[] memory) {
                      return auction(_set).combinedCurrentSetUnits;
                  }
              
                  function getCombinedNextSetUnits(address _set) external view returns (uint256[] memory) {
                      return auction(_set).combinedNextSetUnits;
                  }
              
                  function auctionPriceParameters(address _set)
                      external
                      view
                      returns (RebalancingLibrary.AuctionPriceParameters memory)
                  {
                      return RebalancingLibrary.AuctionPriceParameters({
                          auctionStartTime: auction(_set).startTime,
                          auctionTimeToPivot: auctionPeriod,
                          auctionStartPrice: linearAuction(_set).startPrice,
                          auctionPivotPrice: linearAuction(_set).endPrice
                      });
                  }
              
                  /* ============ Private Functions ============ */
              
                  function clearAuctionState(address _set) private {
                      delete auctions[_set];
                  }
              
                  function auction(address _set) private view returns(Auction.Setup storage) {
                      return linearAuction(_set).auction;
                  }
              
                  function linearAuction(address _set) private view returns(LinearAuction.State storage) {
                      return auctions[_set];
                  }
              
                  function requireValidSet(address _set) private view {
                      require(
                          core.validSets(_set),
                          "LinearAuctionLiquidator: Invalid or disabled proposed SetToken address"
                      );
                  }
              }