ETH Price: $2,493.10 (-0.17%)

Transaction Decoder

Block:
13515629 at Oct-30-2021 01:35:38 AM +UTC
Transaction Fee:
0.01926267602481899 ETH $48.00
Gas Used:
187,835 Gas / 102.551047594 Gwei

Emitted Events:

223 SushiToken.Transfer( from=[Receiver] StakeRewarder, to=VestingMultiVault, value=0 )
224 SushiToken.Approval( owner=[Receiver] StakeRewarder, spender=VestingMultiVault, value=115792089237316195423570985008687907853269984665640557252807484203805666766754 )
225 VestingMultiVault.Issued( beneficiary=[Sender] 0x1db31846acc2b38a4bae97cc288b5687f603990f, allocationId=5, amount=0, start=1635557738, cliff=15811200, duration=15811200 )
226 StakeRewarder.Claim( user=[Sender] 0x1db31846acc2b38a4bae97cc288b5687f603990f, amount=0 )
227 SushiToken.Transfer( from=[Receiver] StakeRewarder, to=[Sender] 0x1db31846acc2b38a4bae97cc288b5687f603990f, value=1 )
228 StakeRewarder.Withdraw( user=[Sender] 0x1db31846acc2b38a4bae97cc288b5687f603990f, pid=1, amount=1 )

Account State Difference:

  Address   Before After State Difference Code
0x1db31846...7F603990F
0.446146968734487404 Eth
Nonce: 12
0.426884292709668414 Eth
Nonce: 13
0.01926267602481899
0x5166E096...736a83575
(Nanopool)
3,685.604434127990851833 Eth3,685.604715880490851833 Eth0.0002817525
0xb632373A...B76A38fBb
0xcf9FAD8B...8Dbf688e8

Execution Trace

StakeRewarder.withdraw( _pid=1, _amount=1 )
  • SushiToken.balanceOf( account=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8 ) => ( 2376784420548264363190206 )
    • SushiToken.balanceOf( account=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8 ) => ( 2376784420548264363190206 )
    • VestingMultiVault.issue( _beneficiary=0x1db31846AcC2B38a4bAE97cc288B5687F603990F, _amount=0, _startAt=1635557738, _cliff=15811200, _duration=15811200, _initialPct=0 )
      • SushiToken.allowance( owner=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8, spender=0xb632373Aab2D6fb1aeb628bea65A6F4B76A38fBb ) => ( 115792089237316195423570985008687907853269984665640557252807484203805666766754 )
        • SushiToken.allowance( owner=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8, spender=0xb632373Aab2D6fb1aeb628bea65A6F4B76A38fBb ) => ( 115792089237316195423570985008687907853269984665640557252807484203805666766754 )
        • SushiToken.transferFrom( sender=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8, recipient=0xb632373Aab2D6fb1aeb628bea65A6F4B76A38fBb, amount=0 ) => ( True )
          • SushiToken.transferFrom( sender=0xcf9FAD8BC125EbB96e27318fF9159108Dbf688e8, recipient=0xb632373Aab2D6fb1aeb628bea65A6F4B76A38fBb, amount=0 ) => ( True )
          • SushiToken.transfer( recipient=0x1db31846AcC2B38a4bAE97cc288B5687F603990F, amount=1 ) => ( True )
            • SushiToken.transfer( recipient=0x1db31846AcC2B38a4bAE97cc288B5687F603990F, amount=1 ) => ( True )
              File 1 of 4: StakeRewarder
              /**
               *Submitted for verification at Etherscan.io on 2021-06-28
              */
              
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              // SPDX-License-Identifier: MIT
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
              
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
              
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/utils/math/SafeMath.sol
              
              
              pragma solidity ^0.8.0;
              
              // CAUTION
              // This version of SafeMath should only be used with Solidity 0.8 or later,
              // because it relies on the compiler's built in overflow checks.
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations.
               *
               * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
               * now has built in overflow checking.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                  }
              
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          // 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-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                  }
              
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                  }
              
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a + b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a * b;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator.
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a % b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/Context.sol
              
              
              pragma solidity ^0.8.0;
              
              /*
               * @dev Provides information about the current execution context, including the
               * sender of the transaction and its data. While these are generally available
               * via msg.sender and msg.data, they should not be accessed in such a direct
               * manner, since when dealing with meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract Context {
                  function _msgSender() internal view virtual returns (address) {
                      return msg.sender;
                  }
              
                  function _msgData() internal view virtual returns (bytes calldata) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/access/Ownable.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Contract module which provides a basic access control mechanism, where
               * there is an account (an owner) that can be granted exclusive access to
               * specific functions.
               *
               * By default, the owner account will be the one that deploys the contract. This
               * can later be changed with {transferOwnership}.
               *
               * This module is used through inheritance. It will make available the modifier
               * `onlyOwner`, which can be applied to your functions to restrict their use to
               * the owner.
               */
              abstract contract Ownable is Context {
                  address private _owner;
              
                  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              
                  /**
                   * @dev Initializes the contract setting the deployer as the initial owner.
                   */
                  constructor () {
                      address msgSender = _msgSender();
                      _owner = msgSender;
                      emit OwnershipTransferred(address(0), msgSender);
                  }
              
                  /**
                   * @dev Returns the address of the current owner.
                   */
                  function owner() public view virtual returns (address) {
                      return _owner;
                  }
              
                  /**
                   * @dev Throws if called by any account other than the owner.
                   */
                  modifier onlyOwner() {
                      require(owner() == _msgSender(), "Ownable: caller is not the owner");
                      _;
                  }
              
                  /**
                   * @dev Leaves the contract without owner. It will not be possible to call
                   * `onlyOwner` functions anymore. Can only be called by the current owner.
                   *
                   * NOTE: Renouncing ownership will leave the contract without an owner,
                   * thereby removing any functionality that is only available to the owner.
                   */
                  function renounceOwnership() public virtual onlyOwner {
                      emit OwnershipTransferred(_owner, address(0));
                      _owner = address(0);
                  }
              
                  /**
                   * @dev Transfers ownership of the contract to a new account (`newOwner`).
                   * Can only be called by the current owner.
                   */
                  function transferOwnership(address newOwner) public virtual onlyOwner {
                      require(newOwner != address(0), "Ownable: new owner is the zero address");
                      emit OwnershipTransferred(_owner, newOwner);
                      _owner = newOwner;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/Address.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol
              
              
              pragma solidity ^0.8.0;
              
              
              
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using Address for address;
              
                  function safeTransfer(IERC20 token, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
              
                  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                  }
              
                  /**
                   * @dev Deprecated. This function has issues similar to the ones found in
                   * {IERC20-approve}, and its usage is discouraged.
                   *
                   * Whenever possible, use {safeIncreaseAllowance} and
                   * {safeDecreaseAllowance} instead.
                   */
                  function safeApprove(IERC20 token, address spender, uint256 value) internal {
                      // safeApprove should only be called when setting an initial allowance,
                      // or when resetting it to zero. To increase and decrease it, use
                      // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                      // solhint-disable-next-line max-line-length
                      require((value == 0) || (token.allowance(address(this), spender) == 0),
                          "SafeERC20: approve from non-zero to non-zero allowance"
                      );
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                  }
              
                  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender) + value;
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      unchecked {
                          uint256 oldAllowance = token.allowance(address(this), spender);
                          require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                          uint256 newAllowance = oldAllowance - value;
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                      }
                  }
              
                  /**
                   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                   * on the return value: the return value is optional (but if data is returned, it must not be false).
                   * @param token The token targeted by the call.
                   * @param data The call data (encoded using abi.encode or one of its variants).
                   */
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                      // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                      // the target address contains contract code and also asserts for success in the low-level call.
              
                      bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                      if (returndata.length > 0) { // Return data is optional
                          // solhint-disable-next-line max-line-length
                          require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/introspection/IERC165.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Interface of the ERC165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[EIP].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                  /**
                   * @dev Returns true if this contract implements the interface defined by
                   * `interfaceId`. See the corresponding
                   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                   * to learn more about how these ids are created.
                   *
                   * This function call must use less than 30 000 gas.
                   */
                  function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              
              // File: openzeppelin-solidity/contracts/utils/introspection/ERC165.sol
              
              
              pragma solidity ^0.8.0;
              
              
              /**
               * @dev Implementation of the {IERC165} interface.
               *
               * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
               * for the additional interface id that will be supported. For example:
               *
               * ```solidity
               * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
               *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
               * }
               * ```
               *
               * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
               */
              abstract contract ERC165 is IERC165 {
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      return interfaceId == type(IERC165).interfaceId;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/Strings.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev String operations.
               */
              library Strings {
                  bytes16 private constant alphabet = "0123456789abcdef";
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                   */
                  function toString(uint256 value) internal pure returns (string memory) {
                      // Inspired by OraclizeAPI's implementation - MIT licence
                      // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
              
                      if (value == 0) {
                          return "0";
                      }
                      uint256 temp = value;
                      uint256 digits;
                      while (temp != 0) {
                          digits++;
                          temp /= 10;
                      }
                      bytes memory buffer = new bytes(digits);
                      while (value != 0) {
                          digits -= 1;
                          buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                          value /= 10;
                      }
                      return string(buffer);
                  }
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                   */
                  function toHexString(uint256 value) internal pure returns (string memory) {
                      if (value == 0) {
                          return "0x00";
                      }
                      uint256 temp = value;
                      uint256 length = 0;
                      while (temp != 0) {
                          length++;
                          temp >>= 8;
                      }
                      return toHexString(value, length);
                  }
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                   */
                  function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                      bytes memory buffer = new bytes(2 * length + 2);
                      buffer[0] = "0";
                      buffer[1] = "x";
                      for (uint256 i = 2 * length + 1; i > 1; --i) {
                          buffer[i] = alphabet[value & 0xf];
                          value >>= 4;
                      }
                      require(value == 0, "Strings: hex length insufficient");
                      return string(buffer);
                  }
              
              }
              
              // File: openzeppelin-solidity/contracts/access/AccessControl.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev External interface of AccessControl declared to support ERC165 detection.
               */
              interface IAccessControl {
                  function hasRole(bytes32 role, address account) external view returns (bool);
                  function getRoleAdmin(bytes32 role) external view returns (bytes32);
                  function grantRole(bytes32 role, address account) external;
                  function revokeRole(bytes32 role, address account) external;
                  function renounceRole(bytes32 role, address account) external;
              }
              
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms. This is a lightweight version that doesn't allow enumerating role
               * members except through off-chain means by accessing the contract event logs. Some
               * applications may benefit from on-chain enumerability, for those cases see
               * {AccessControlEnumerable}.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it.
               */
              abstract contract AccessControl is Context, IAccessControl, ERC165 {
                  struct RoleData {
                      mapping (address => bool) members;
                      bytes32 adminRole;
                  }
              
                  mapping (bytes32 => RoleData) private _roles;
              
                  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
              
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   *
                   * _Available since v3.1._
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
              
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call, an admin role
                   * bearer except when using {_setupRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Modifier that checks that an account has a specific role. Reverts
                   * with a standardized message including the required role.
                   *
                   * The format of the revert reason is given by the following regular expression:
                   *
                   *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
                   *
                   * _Available since v4.1._
                   */
                  modifier onlyRole(bytes32 role) {
                      _checkRole(role, _msgSender());
                      _;
                  }
              
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      return interfaceId == type(IAccessControl).interfaceId
                          || super.supportsInterface(interfaceId);
                  }
              
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) public view override returns (bool) {
                      return _roles[role].members[account];
                  }
              
                  /**
                   * @dev Revert with a standard message if `account` is missing `role`.
                   *
                   * The format of the revert reason is given by the following regular expression:
                   *
                   *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
                   */
                  function _checkRole(bytes32 role, address account) internal view {
                      if(!hasRole(role, account)) {
                          revert(string(abi.encodePacked(
                              "AccessControl: account ",
                              Strings.toHexString(uint160(account), 20),
                              " is missing role ",
                              Strings.toHexString(uint256(role), 32)
                          )));
                      }
                  }
              
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                      return _roles[role].adminRole;
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `account`.
                   */
                  function renounceRole(bytes32 role, address account) public virtual override {
                      require(account == _msgSender(), "AccessControl: can only renounce roles for self");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event. Note that unlike {grantRole}, this function doesn't perform any
                   * checks on the calling account.
                   *
                   * [WARNING]
                   * ====
                   * This function should only be called from the constructor when setting
                   * up the initial roles for the system.
                   *
                   * Using this function in any other way is effectively circumventing the admin
                   * system imposed by {AccessControl}.
                   * ====
                   */
                  function _setupRole(bytes32 role, address account) internal virtual {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Sets `adminRole` as ``role``'s admin role.
                   *
                   * Emits a {RoleAdminChanged} event.
                   */
                  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                      emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
                      _roles[role].adminRole = adminRole;
                  }
              
                  function _grantRole(bytes32 role, address account) private {
                      if (!hasRole(role, account)) {
                          _roles[role].members[account] = true;
                          emit RoleGranted(role, account, _msgSender());
                      }
                  }
              
                  function _revokeRole(bytes32 role, address account) private {
                      if (hasRole(role, account)) {
                          _roles[role].members[account] = false;
                          emit RoleRevoked(role, account, _msgSender());
                      }
                  }
              }
              
              // File: contracts/VestingMultiVault.sol
              
              pragma solidity ^0.8.0;
              
              
              
              
              
              /**
               * @title VestingMultiVault
               * @dev A token vesting contract that will release tokens gradually like a
               * standard equity vesting schedule, with a cliff and vesting period but no
               * arbitrary restrictions on the frequency of claims. Optionally has an initial
               * tranche claimable immediately after the cliff expires (in addition to any
               * amounts that would have vested up to that point but didn't due to a cliff).
               */
              contract VestingMultiVault is AccessControl {
                  using SafeMath for uint256;
                  using SafeERC20 for IERC20;
              
                  event Issued(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 amount,
                      uint256 start,
                      uint256 cliff,
                      uint256 duration
                  );
              
                  event Released(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 amount,
                      uint256 remaining
                  );
                  
                  event Revoked(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 allocationAmount,
                      uint256 revokedAmount
                  );
              
                  struct Allocation {
                      uint256 start;
                      uint256 cliff;
                      uint256 duration;
                      uint256 total;
                      uint256 claimed;
                      uint256 initial;
                  }
              
                  // The token being vested.
                  IERC20 public immutable token;
              
                  // The amount unclaimed for an address, whether or not vested.
                  mapping(address => uint256) public pendingAmount;
              
                  // The allocations assigned to an address.
                  mapping(address => Allocation[]) public userAllocations;
              
                  // The precomputed hash of the "ISSUER" role.
                  bytes32 public constant ISSUER = keccak256("ISSUER");
              
                  /**
                   * @dev Creates a vesting contract that releases allocations of a token
                   * over an arbitrary time period with support for tranches and cliffs.
                   * @param _token The ERC-20 token to be vested
                   */
                  constructor(IERC20 _token) {
                      token = _token;
                      _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                      _setupRole(ISSUER, msg.sender);
                  }
              
                  /**
                   * @dev Creates a new allocation for a beneficiary. Tokens are released
                   * linearly over time until a given number of seconds have passed since the
                   * start of the vesting schedule. Callable only by issuers.
                   * @param _beneficiary The address to which tokens will be released
                   * @param _amount The amount of the allocation (in wei)
                   * @param _startAt The unix timestamp at which the vesting may begin
                   * @param _cliff The number of seconds after _startAt before which no vesting occurs
                   * @param _duration The number of seconds after which the entire allocation is vested
                   * @param _initialPct The percentage of the allocation initially available (integer, 0-100)
                   */
                  function issue(
                      address _beneficiary,
                      uint256 _amount,
                      uint256 _startAt,
                      uint256 _cliff,
                      uint256 _duration,
                      uint256 _initialPct
                  ) public onlyRole(ISSUER) {
                      require(token.allowance(msg.sender, address(this)) >= _amount, "Token allowance not sufficient");
                      require(_beneficiary != address(0), "Cannot grant tokens to the zero address");
                      require(_cliff <= _duration, "Cliff must not exceed duration");
                      require(_initialPct <= 100, "Initial release percentage must be an integer 0 to 100 (inclusive)");
              
                      // Pull the number of tokens required for the allocation.
                      token.safeTransferFrom(msg.sender, address(this), _amount);
              
                      // Increase the total pending for the address.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].add(_amount);
              
                      // Push the new allocation into the stack.
                      userAllocations[_beneficiary].push(Allocation({
                          claimed:    0,
                          cliff:      _cliff,
                          duration:   _duration,
                          initial:    _amount.mul(_initialPct).div(100),
                          start:      _startAt,
                          total:      _amount
                      }));
                      
                      emit Issued(
                          _beneficiary,
                          userAllocations[_beneficiary].length - 1,
                          _amount,
                          _startAt,
                          _cliff,
                          _duration
                      );
                  }
                  
                  /**
                   * @dev Revokes an existing allocation. Any unclaimed tokens are recalled
                   * and sent to the caller. Callable only be issuers.
                   * @param _beneficiary The address whose allocation is to be revoked
                   * @param _id The allocation ID to revoke
                   */
                  function revoke(
                      address _beneficiary,
                      uint256 _id
                  ) public onlyRole(ISSUER) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      
                      // Calculate the remaining amount.
                      uint256 total = allocation.total;
                      uint256 remainder = total.sub(allocation.claimed);
              
                      // Update the total pending for the address.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].sub(remainder);
              
                      // Update the allocation to be claimed in full.
                      allocation.claimed = total;
                      
                      // Transfer the tokens vested 
                      token.safeTransfer(msg.sender, remainder);
                      emit Revoked(
                          _beneficiary,
                          _id,
                          total,
                          remainder
                      );
                  }
              
                  /**
                   * @dev Transfers vested tokens from an allocation to its beneficiary. Callable by anyone.
                   * @param _beneficiary The address that has vested tokens
                   * @param _id The vested allocation index
                   */
                  function release(
                      address _beneficiary,
                      uint256 _id
                  ) public {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
              
                      // Calculate the releasable amount.
                      uint256 amount = _releasableAmount(allocation);
                      require(amount > 0, "Nothing to release");
                      
                      // Add the amount to the allocation's total claimed.
                      allocation.claimed = allocation.claimed.add(amount);
              
                      // Subtract the amount from the beneficiary's total pending.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].sub(amount);
              
                      // Transfer the tokens to the beneficiary.
                      token.safeTransfer(_beneficiary, amount);
              
                      emit Released(
                          _beneficiary,
                          _id,
                          amount,
                          allocation.total.sub(allocation.claimed)
                      );
                  }
                  
                  /**
                   * @dev Transfers vested tokens from any number of allocations to their beneficiary. Callable by anyone. May be gas-intensive.
                   * @param _beneficiary The address that has vested tokens
                   * @param _ids The vested allocation indexes
                   */
                  function releaseMultiple(
                      address _beneficiary,
                      uint256[] calldata _ids
                  ) external {
                      for (uint256 i = 0; i < _ids.length; i++) {
                          release(_beneficiary, _ids[i]);
                      }
                  }
                  
                  /**
                   * @dev Gets the number of allocations issued for a given address.
                   * @param _beneficiary The address to check for allocations
                   */
                  function allocationCount(
                      address _beneficiary
                  ) public view returns (uint256 count) {
                      return userAllocations[_beneficiary].length;
                  }
                  
                  /**
                   * @dev Calculates the amount that has already vested but has not yet been released for a given address.
                   * @param _beneficiary Address to check
                   * @param _id The allocation index
                   */
                  function releasableAmount(
                      address _beneficiary,
                      uint256 _id
                  ) public view returns (uint256 amount) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      return _releasableAmount(allocation);
                  }
                  
                  /**
                   * @dev Gets the total releasable for a given address. Likely gas-intensive, not intended for contract use.
                   * @param _beneficiary Address to check
                   */
                  function totalReleasableAount(
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      for (uint256 i = 0; i < allocationCount(_beneficiary); i++) {
                          amount = amount.add(releasableAmount(_beneficiary, i));
                      }
                      return amount;
                  }
                  
                  /**
                   * @dev Calculates the amount that has vested to date.
                   * @param _beneficiary Address to check
                   * @param _id The allocation index
                   */
                  function vestedAmount(
                      address _beneficiary,
                      uint256 _id
                  ) public view returns (uint256) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      return _vestedAmount(allocation);
                  }
                  
                  /**
                   * @dev Gets the total ever vested for a given address. Likely gas-intensive, not intended for contract use.
                   * @param _beneficiary Address to check
                   */
                  function totalVestedAount(
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      for (uint256 i = 0; i < allocationCount(_beneficiary); i++) {
                          amount = amount.add(vestedAmount(_beneficiary, i));
                      }
                      return amount;
                  }
              
                  /**
                   * @dev Calculates the amount that has already vested but hasn't been released yet.
                   * @param allocation Allocation to calculate against
                   */
                  function _releasableAmount(
                      Allocation storage allocation
                  ) internal view returns (uint256) {
                      return _vestedAmount(allocation).sub(allocation.claimed);
                  }
              
                  /**
                   * @dev Calculates the amount that has already vested.
                   * @param allocation Allocation to calculate against
                   */
                  function _vestedAmount(
                      Allocation storage allocation
                  ) internal view returns (uint256 amount) {
                      if (block.timestamp < allocation.start.add(allocation.cliff)) {
                          // Nothing is vested until after the start time + cliff length.
                          amount = 0;
                      } else if (block.timestamp >= allocation.start.add(allocation.duration)) {
                          // The entire amount has vested if the entire duration has elapsed.
                          amount = allocation.total;
                      } else {
                          // The initial tranche is available once the cliff expires, plus any portion of
                          // tokens which have otherwise become vested as of the current block's timestamp.
                          amount = allocation.initial.add(
                              allocation.total
                                  .sub(allocation.initial)
                                  .sub(amount)
                                  .mul(block.timestamp.sub(allocation.start))
                                  .div(allocation.duration)
                          );
                      }
                      
                      return amount;
                  }
              }
              
              // File: contracts/StakeRewarder.sol
              
              pragma solidity ^0.8.5;
              
              /**
               * @title StakeRewarder
               * @dev This contract distributes rewards to depositors of supported tokens.
               * It's based on Sushi's MasterChef v1, but notably only serves what's already
               * available: no new tokens can be created. It's just a restaurant, not a farm.
               */
              contract StakeRewarder is Ownable {
                  using SafeMath for uint256;
                  using SafeERC20 for IERC20;
                  
                  struct UserInfo {
                      uint256 amount;     // Quantity of tokens the user has staked.
                      uint256 rewardDebt; // Reward debt. See explanation below.
                      // We do some fancy math here. Basically, any point in time, the
                      // amount of rewards entitled to a user but is pending to be distributed is:
                      //
                      //   pendingReward = (stakedAmount * pool.accPerShare) - user.rewardDebt
                      //
                      // Whenever a user deposits or withdraws tokens in a pool:
                      //   1. The pool's `accPerShare` (and `lastRewardBlock`) gets updated.
                      //   2. User's pending rewards are issued (greatly simplifies accounting).
                      //   3. User's `amount` gets updated.
                      //   4. User's `rewardDebt` gets updated.
                  }
                  
                  struct PoolInfo {
                      IERC20 token;            // Address of the token contract.
                      uint256 weight;          // Weight points assigned to this pool.
                      uint256 power;           // The multiplier for determining "staking power".
                      uint256 total;           // Total number of tokens staked.
                      uint256 accPerShare;     // Accumulated rewards per share (times 1e12).
                      uint256 lastRewardBlock; // Last block where rewards were calculated.
                  }
                  
                  // Distribution vault.
                  VestingMultiVault public immutable vault;
                  
                  // Reward configuration.
                  IERC20 public immutable rewardToken;
                  uint256 public rewardPerBlock;
                  uint256 public vestingCliff;
                  uint256 public vestingDuration;
                  
                  // Housekeeping for each pool.
                  PoolInfo[] public poolInfo;
                  
                  // Info of each user that stakes tokens.
                  mapping(uint256 => mapping(address => UserInfo)) public userInfo;
                  
                  // Underpaid rewards owed to a user.
                  mapping(address => uint256) public underpayment;
                  
                  // The sum of weights across all staking tokens.
                  uint256 public totalWeight = 0;
                  
                  // The block number when staking starts.
                  uint256 public startBlock;
                  
                  event TokenAdded(address indexed token, uint256 weight, uint256 totalWeight);
                  event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
                  event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
                  event Claim(address indexed user, uint256 amount);
                  event EmergencyReclaim(address indexed user, address token, uint256 amount);
                  event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
              
                  /**
                   * @dev Create a staking contract that rewards depositors using its own token balance
                   * and optionally vests rewards over time.
                   * @param _rewardToken The token to be distributed as rewards.
                   * @param _rewardPerBlock The quantity of reward tokens accrued per block.
                   * @param _startBlock The first block at which staking is allowed.
                   * @param _vestingCliff The number of seconds until issued rewards begin vesting.
                   * @param _vestingDuration The number of seconds after issuance until vesting is completed.
                   * @param _vault The VestingMultiVault that is ultimately responsible for reward distribution.
                   */
                  constructor(
                      IERC20 _rewardToken,
                      uint256 _rewardPerBlock,
                      uint256 _startBlock,
                      uint256 _vestingCliff,
                      uint256 _vestingDuration,
                      VestingMultiVault _vault
                  ) {
                      // Set the initial reward config
                      rewardPerBlock = _rewardPerBlock;
                      startBlock = _startBlock;
                      vestingCliff = _vestingCliff;
                      vestingDuration = _vestingDuration;
                      
                      // Set the vault and reward token (immutable after creation)
                      vault = _vault;
                      rewardToken = _rewardToken;
                      
                      // Approve the vault to pull reward tokens
                      _rewardToken.approve(address(_vault), 2**256 - 1);
                  }
              
                  /**
                   * @dev Adds a new staking pool to the stack. Can only be called by the owner.
                   * @param _token The token to be staked.
                   * @param _weight The weight of this pool (used to determine proportion of rewards relative to the total weight).
                   * @param _power The power factor of this pool (used as a multiple of tokens staked, e.g. for determining voting power).
                   * @param _shouldUpdate Whether to update all pools first.
                   */
                  function createPool(
                      IERC20 _token,
                      uint256 _weight,
                      uint256 _power,
                      bool _shouldUpdate
                  ) public onlyOwner {
                      if (_shouldUpdate) {
                          pokePools();
                      }
              
                      uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;
                      totalWeight = totalWeight.add(_weight);
                      poolInfo.push(
                          PoolInfo({
                              token: _token,
                              weight: _weight,
                              power: _power,
                              total: 0,
                              accPerShare: 0,
                              lastRewardBlock: lastRewardBlock
                          })
                      );
                  }
              
                  /**
                   * @dev Update the given staking pool's weight and power. Can only be called by the owner.
                   * @param _pid The pool identifier.
                   * @param _weight The weight of this pool (used to determine proportion of rewards relative to the total weight).
                   * @param _power The power of this pool's token (used as a multiplier of tokens staked, e.g. for voting).
                   * @param _shouldUpdate Whether to update all pools first.
                   */ 
                  function updatePool(
                      uint256 _pid,
                      uint256 _weight,
                      uint256 _power,
                      bool _shouldUpdate
                  ) public onlyOwner {
                      if (_shouldUpdate) {
                          pokePools();
                      }
                      
                      totalWeight = totalWeight.sub(poolInfo[_pid].weight).add(
                          _weight
                      );
              
                      poolInfo[_pid].weight = _weight;
                      poolInfo[_pid].power = _power;
                  }
                  
                  /**
                   * @dev Update the reward per block. Can only be called by the owner.
                   * @param _rewardPerBlock The total quantity to distribute per block.
                   */
                  function setRewardPerBlock(
                      uint256 _rewardPerBlock
                  ) public onlyOwner {
                      rewardPerBlock = _rewardPerBlock;
                  }
                  
                  /**
                   * @dev Update the vesting rules for rewards. Can only be called by the owner.
                   * @param _duration the number of seconds over which vesting occurs (see VestingMultiVault)
                   * @param _cliff the number of seconds before any release occurs (see VestingMultiVault)
                   */
                  function setVestingRules(
                      uint256 _duration,
                      uint256 _cliff
                  ) public onlyOwner {
                      vestingDuration = _duration;
                      vestingCliff = _cliff;
                  }
              
                  /**
                   * @dev Calculate elapsed blocks between `_from` and `_to`.
                   * @param _from The starting block.
                   * @param _to The ending block.
                   */
                  function duration(
                      uint256 _from,
                      uint256 _to
                  ) public pure returns (uint256) {
                      return _to.sub(_from);
                  }
                  
                  function totalPendingRewards(
                      address _beneficiary
                  ) public view returns (uint256 total) {
                      for (uint256 pid = 0; pid < poolInfo.length; pid++) {
                          total = total.add(pendingRewards(pid, _beneficiary));
                      }
              
                      return total;
                  }
              
                  /**
                   * @dev View function to see pending rewards for an address. Likely gas intensive.
                   * @param _pid The pool identifier.
                   * @param _beneficiary The address to check.
                   */
                  function pendingRewards(
                      uint256 _pid,
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][_beneficiary];
                      uint256 accPerShare = pool.accPerShare;
                      uint256 tokenSupply = pool.total;
                      
                      if (block.number > pool.lastRewardBlock && tokenSupply != 0) {
                          uint256 reward = duration(pool.lastRewardBlock, block.number)
                              .mul(rewardPerBlock)
                              .mul(pool.weight)
                              .div(totalWeight);
              
                          accPerShare = accPerShare.add(
                              reward.mul(1e12).div(tokenSupply)
                          );
                      }
              
                      return user.amount.mul(accPerShare).div(1e12).sub(user.rewardDebt);
                  }
              
                  /**
                   * @dev Gets the sum of power for every pool. Likely gas intensive.
                   * @param _beneficiary The address to check.
                   */
                  function totalPower(
                      address _beneficiary
                  ) public view returns (uint256 total) {
                      for (uint256 pid = 0; pid < poolInfo.length; pid++) {
                          total = total.add(power(pid, _beneficiary));
                      }
              
                      return total;
                  }
              
                  /**
                   * @dev Gets power for a single pool.
                   * @param _pid The pool identifier.
                   * @param _beneficiary The address to check.
                   */
                  function power(
                      uint256 _pid,
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][_beneficiary];
                      return pool.power.mul(user.amount);
                  }
              
                  /**
                   * @dev Update all pools. Callable by anyone. Could be gas intensive.
                   */
                  function pokePools() public {
                      uint256 length = poolInfo.length;
                      for (uint256 pid = 0; pid < length; ++pid) {
                          pokePool(pid);
                      }
                  }
              
                  /**
                   * @dev Update rewards of the given pool to be up-to-date. Callable by anyone.
                   * @param _pid The pool identifier.
                   */
                  function pokePool(
                      uint256 _pid
                  ) public {
                      PoolInfo storage pool = poolInfo[_pid];
              
                      if (block.number <= pool.lastRewardBlock) {
                          return;
                      }
              
                      uint256 tokenSupply = pool.total;
                      if (tokenSupply == 0) {
                          pool.lastRewardBlock = block.number;
                          return;
                      }
              
                      uint256 reward = duration(pool.lastRewardBlock, block.number)
                          .mul(rewardPerBlock)
                          .mul(pool.weight)
                          .div(totalWeight);
              
                      pool.accPerShare = pool.accPerShare.add(
                          reward.mul(1e12).div(tokenSupply)
                      );
              
                      pool.lastRewardBlock = block.number;
                  }
              
                  /**
                   * @dev Claim rewards not yet distributed for an address. Callable by anyone.
                   * @param _pid The pool identifier.
                   * @param _beneficiary The address to claim for.
                   */
                  function claim(
                      uint256 _pid,
                      address _beneficiary
                  ) public {
                      // make sure the pool is up-to-date
                      pokePool(_pid);
              
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][_beneficiary];
              
                      _claim(pool, user, _beneficiary);
                  }
                  
                  /**
                   * @dev Claim rewards from multiple pools. Callable by anyone.
                   * @param _pids An array of pool identifiers.
                   * @param _beneficiary The address to claim for.
                   */
                  function claimMultiple(
                      uint256[] calldata _pids,
                      address _beneficiary
                  ) external {
                      for (uint256 i = 0; i < _pids.length; i++) {
                          claim(_pids[i], _beneficiary);
                      }
                  }
              
                  /**
                   * @dev Stake tokens to earn a share of rewards.
                   * @param _pid The pool identifier.
                   * @param _amount The number of tokens to deposit.
                   */
                  function deposit(
                      uint256 _pid,
                      uint256 _amount
                  ) public {
                      require(_amount > 0, "deposit: only non-zero amounts allowed");
                      
                      // make sure the pool is up-to-date
                      pokePool(_pid);
              
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][msg.sender];
                      
                      // deliver any pending rewards
                      _claim(pool, user, msg.sender);
                      
                      // pull in user's staked assets
                      pool.token.safeTransferFrom(
                          address(msg.sender),
                          address(this),
                          _amount
                      );
              
                      // update the pool's total deposit
                      pool.total = pool.total.add(_amount);
                      
                      // update user's deposit and reward info
                      user.amount = user.amount.add(_amount);
                      user.rewardDebt = user.amount.mul(pool.accPerShare).div(1e12);
                      
                      emit Deposit(msg.sender, _pid, _amount);
                  }
              
                  /**
                   * @dev Withdraw staked tokens and any pending rewards.
                   */
                  function withdraw(
                      uint256 _pid,
                      uint256 _amount
                  ) public {
                      require(_amount > 0, "withdraw: only non-zero amounts allowed");
              
                      // make sure the pool is up-to-date
                      pokePool(_pid);
                      
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][msg.sender];
                      
                      require(user.amount >= _amount, "withdraw: amount too large");
                      
                      // deliver any pending rewards
                      _claim(pool, user, msg.sender);
              
                      // update the pool's total deposit
                      pool.total = pool.total.sub(_amount);
                      
                      // update the user's deposit and reward info
                      user.amount = user.amount.sub(_amount);
                      user.rewardDebt = user.amount.mul(pool.accPerShare).div(1e12);
                      
                      // send back the staked assets
                      pool.token.safeTransfer(address(msg.sender), _amount);
                      
                      emit Withdraw(msg.sender, _pid, _amount);
                  }
              
                  /**
                   * @dev Withdraw staked tokens and forego any unclaimed rewards. This is a fail-safe.
                   */
                  function emergencyWithdraw(
                      uint256 _pid
                  ) public {
                      PoolInfo storage pool = poolInfo[_pid];
                      UserInfo storage user = userInfo[_pid][msg.sender];
                      uint256 amount = user.amount;
                      
                      // reset everything to zero
                      user.amount = 0;
                      user.rewardDebt = 0;
                      underpayment[msg.sender] = 0;
              
                      // update the pool's total deposit
                      pool.total = pool.total.sub(amount);
                      
                      // send back the staked assets
                      pool.token.safeTransfer(address(msg.sender), amount);
                      emit EmergencyWithdraw(msg.sender, _pid, amount);
                  }
                  
                  /**
                   * @dev Reclaim stuck tokens (e.g. unexpected external rewards). This is a fail-safe.
                   */
                  function emergencyReclaim(
                      IERC20 _token,
                      uint256 _amount
                  ) public onlyOwner {
                      if (_amount == 0) {
                          _amount = _token.balanceOf(address(this));
                      }
                      
                      _token.transfer(msg.sender, _amount);
                      emit EmergencyReclaim(msg.sender, address(_token), _amount);
                  }
                  
                  /**
                   * @dev Gets the length of the pools array.
                   */
                  function poolLength() external view returns (uint256 length) {
                      return poolInfo.length;
                  }
                  
                  /**
                   * @dev Claim rewards not yet distributed for an address.
                   * @param pool The staking pool issuing rewards.
                   * @param user The staker who earned them.
                   * @param to The address to pay. 
                   */
                  function _claim(
                      PoolInfo storage pool,
                      UserInfo storage user,
                      address to
                  ) internal {
                      if (user.amount > 0) {
                          // calculate the pending reward
                          uint256 pending = user.amount
                              .mul(pool.accPerShare)
                              .div(1e12)
                              .sub(user.rewardDebt)
                              .add(underpayment[to]);
                          
                          // send the rewards out
                          uint256 payout = _safelyDistribute(to, pending);
                          if (payout < pending) {
                              underpayment[to] = pending.sub(payout);
                          } else {
                              underpayment[to] = 0;
                          }
                          
                          emit Claim(to, payout);
                      }
                  }
                  
                  /**
                   * @dev Safely distribute at most the amount of tokens in holding.
                   */
                  function _safelyDistribute(
                      address _to,
                      uint256 _amount
                  ) internal returns (uint256 amount) {
                      uint256 available = rewardToken.balanceOf(address(this));
                      amount = _amount > available ? available : _amount;
                      
                      vault.issue(
                          _to,                // address _beneficiary,
                          _amount,            // uint256 _amount,
                          block.timestamp,    // uint256 _startAt,
                          vestingCliff,       // uint256 _cliff,
                          vestingDuration,    // uint256 _duration,
                          0                   // uint256 _initialPct
                      );
                      
                      return amount;
                  }
              }

              File 2 of 4: VestingMultiVault
              // SPDX-License-Identifier: MIT
              // File: openzeppelin-solidity/contracts/utils/Address.sol
              
              
              pragma solidity ^0.8.0;
              
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol
              
              
              pragma solidity ^0.8.0;
              
              
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using Address for address;
              
                  function safeTransfer(IERC20 token, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                  }
              
                  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                      _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                  }
              
                  /**
                   * @dev Deprecated. This function has issues similar to the ones found in
                   * {IERC20-approve}, and its usage is discouraged.
                   *
                   * Whenever possible, use {safeIncreaseAllowance} and
                   * {safeDecreaseAllowance} instead.
                   */
                  function safeApprove(IERC20 token, address spender, uint256 value) internal {
                      // safeApprove should only be called when setting an initial allowance,
                      // or when resetting it to zero. To increase and decrease it, use
                      // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                      // solhint-disable-next-line max-line-length
                      require((value == 0) || (token.allowance(address(this), spender) == 0),
                          "SafeERC20: approve from non-zero to non-zero allowance"
                      );
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                  }
              
                  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender) + value;
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      unchecked {
                          uint256 oldAllowance = token.allowance(address(this), spender);
                          require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                          uint256 newAllowance = oldAllowance - value;
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                      }
                  }
              
                  /**
                   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                   * on the return value: the return value is optional (but if data is returned, it must not be false).
                   * @param token The token targeted by the call.
                   * @param data The call data (encoded using abi.encode or one of its variants).
                   */
                  function _callOptionalReturn(IERC20 token, bytes memory data) private {
                      // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                      // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                      // the target address contains contract code and also asserts for success in the low-level call.
              
                      bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                      if (returndata.length > 0) { // Return data is optional
                          // solhint-disable-next-line max-line-length
                          require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Interface of the ERC20 standard as defined in the EIP.
               */
              interface IERC20 {
                  /**
                   * @dev Returns the amount of tokens in existence.
                   */
                  function totalSupply() external view returns (uint256);
              
                  /**
                   * @dev Returns the amount of tokens owned by `account`.
                   */
                  function balanceOf(address account) external view returns (uint256);
              
                  /**
                   * @dev Moves `amount` tokens from the caller's account to `recipient`.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transfer(address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Returns the remaining number of tokens that `spender` will be
                   * allowed to spend on behalf of `owner` through {transferFrom}. This is
                   * zero by default.
                   *
                   * This value changes when {approve} or {transferFrom} are called.
                   */
                  function allowance(address owner, address spender) external view returns (uint256);
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * IMPORTANT: Beware that changing an allowance with this method brings the risk
                   * that someone may use both the old and the new allowance by unfortunate
                   * transaction ordering. One possible solution to mitigate this race
                   * condition is to first reduce the spender's allowance to 0 and set the
                   * desired value afterwards:
                   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                   *
                   * Emits an {Approval} event.
                   */
                  function approve(address spender, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Moves `amount` tokens from `sender` to `recipient` using the
                   * allowance mechanism. `amount` is then deducted from the caller's
                   * allowance.
                   *
                   * Returns a boolean value indicating whether the operation succeeded.
                   *
                   * Emits a {Transfer} event.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
              
                  /**
                   * @dev Emitted when `value` tokens are moved from one account (`from`) to
                   * another (`to`).
                   *
                   * Note that `value` may be zero.
                   */
                  event Transfer(address indexed from, address indexed to, uint256 value);
              
                  /**
                   * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                   * a call to {approve}. `value` is the new allowance.
                   */
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              }
              
              // File: openzeppelin-solidity/contracts/utils/math/SafeMath.sol
              
              
              pragma solidity ^0.8.0;
              
              // CAUTION
              // This version of SafeMath should only be used with Solidity 0.8 or later,
              // because it relies on the compiler's built in overflow checks.
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations.
               *
               * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
               * now has built in overflow checking.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                  }
              
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          // 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-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                  }
              
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      unchecked {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                  }
              
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a + b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a * b;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator.
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a % b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      unchecked {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/introspection/IERC165.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev Interface of the ERC165 standard, as defined in the
               * https://eips.ethereum.org/EIPS/eip-165[EIP].
               *
               * Implementers can declare support of contract interfaces, which can then be
               * queried by others ({ERC165Checker}).
               *
               * For an implementation, see {ERC165}.
               */
              interface IERC165 {
                  /**
                   * @dev Returns true if this contract implements the interface defined by
                   * `interfaceId`. See the corresponding
                   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                   * to learn more about how these ids are created.
                   *
                   * This function call must use less than 30 000 gas.
                   */
                  function supportsInterface(bytes4 interfaceId) external view returns (bool);
              }
              
              // File: openzeppelin-solidity/contracts/utils/introspection/ERC165.sol
              
              
              pragma solidity ^0.8.0;
              
              
              /**
               * @dev Implementation of the {IERC165} interface.
               *
               * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
               * for the additional interface id that will be supported. For example:
               *
               * ```solidity
               * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
               *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
               * }
               * ```
               *
               * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
               */
              abstract contract ERC165 is IERC165 {
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      return interfaceId == type(IERC165).interfaceId;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/utils/Strings.sol
              
              
              pragma solidity ^0.8.0;
              
              /**
               * @dev String operations.
               */
              library Strings {
                  bytes16 private constant alphabet = "0123456789abcdef";
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                   */
                  function toString(uint256 value) internal pure returns (string memory) {
                      // Inspired by OraclizeAPI's implementation - MIT licence
                      // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
              
                      if (value == 0) {
                          return "0";
                      }
                      uint256 temp = value;
                      uint256 digits;
                      while (temp != 0) {
                          digits++;
                          temp /= 10;
                      }
                      bytes memory buffer = new bytes(digits);
                      while (value != 0) {
                          digits -= 1;
                          buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                          value /= 10;
                      }
                      return string(buffer);
                  }
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                   */
                  function toHexString(uint256 value) internal pure returns (string memory) {
                      if (value == 0) {
                          return "0x00";
                      }
                      uint256 temp = value;
                      uint256 length = 0;
                      while (temp != 0) {
                          length++;
                          temp >>= 8;
                      }
                      return toHexString(value, length);
                  }
              
                  /**
                   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                   */
                  function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                      bytes memory buffer = new bytes(2 * length + 2);
                      buffer[0] = "0";
                      buffer[1] = "x";
                      for (uint256 i = 2 * length + 1; i > 1; --i) {
                          buffer[i] = alphabet[value & 0xf];
                          value >>= 4;
                      }
                      require(value == 0, "Strings: hex length insufficient");
                      return string(buffer);
                  }
              
              }
              
              // File: openzeppelin-solidity/contracts/utils/Context.sol
              
              
              pragma solidity ^0.8.0;
              
              /*
               * @dev Provides information about the current execution context, including the
               * sender of the transaction and its data. While these are generally available
               * via msg.sender and msg.data, they should not be accessed in such a direct
               * manner, since when dealing with meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract Context {
                  function _msgSender() internal view virtual returns (address) {
                      return msg.sender;
                  }
              
                  function _msgData() internal view virtual returns (bytes calldata) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              // File: openzeppelin-solidity/contracts/access/AccessControl.sol
              
              
              pragma solidity ^0.8.0;
              
              
              
              
              /**
               * @dev External interface of AccessControl declared to support ERC165 detection.
               */
              interface IAccessControl {
                  function hasRole(bytes32 role, address account) external view returns (bool);
                  function getRoleAdmin(bytes32 role) external view returns (bytes32);
                  function grantRole(bytes32 role, address account) external;
                  function revokeRole(bytes32 role, address account) external;
                  function renounceRole(bytes32 role, address account) external;
              }
              
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms. This is a lightweight version that doesn't allow enumerating role
               * members except through off-chain means by accessing the contract event logs. Some
               * applications may benefit from on-chain enumerability, for those cases see
               * {AccessControlEnumerable}.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it.
               */
              abstract contract AccessControl is Context, IAccessControl, ERC165 {
                  struct RoleData {
                      mapping (address => bool) members;
                      bytes32 adminRole;
                  }
              
                  mapping (bytes32 => RoleData) private _roles;
              
                  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
              
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   *
                   * _Available since v3.1._
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
              
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call, an admin role
                   * bearer except when using {_setupRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Modifier that checks that an account has a specific role. Reverts
                   * with a standardized message including the required role.
                   *
                   * The format of the revert reason is given by the following regular expression:
                   *
                   *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
                   *
                   * _Available since v4.1._
                   */
                  modifier onlyRole(bytes32 role) {
                      _checkRole(role, _msgSender());
                      _;
                  }
              
                  /**
                   * @dev See {IERC165-supportsInterface}.
                   */
                  function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                      return interfaceId == type(IAccessControl).interfaceId
                          || super.supportsInterface(interfaceId);
                  }
              
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) public view override returns (bool) {
                      return _roles[role].members[account];
                  }
              
                  /**
                   * @dev Revert with a standard message if `account` is missing `role`.
                   *
                   * The format of the revert reason is given by the following regular expression:
                   *
                   *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
                   */
                  function _checkRole(bytes32 role, address account) internal view {
                      if(!hasRole(role, account)) {
                          revert(string(abi.encodePacked(
                              "AccessControl: account ",
                              Strings.toHexString(uint160(account), 20),
                              " is missing role ",
                              Strings.toHexString(uint256(role), 32)
                          )));
                      }
                  }
              
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                      return _roles[role].adminRole;
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `account`.
                   */
                  function renounceRole(bytes32 role, address account) public virtual override {
                      require(account == _msgSender(), "AccessControl: can only renounce roles for self");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event. Note that unlike {grantRole}, this function doesn't perform any
                   * checks on the calling account.
                   *
                   * [WARNING]
                   * ====
                   * This function should only be called from the constructor when setting
                   * up the initial roles for the system.
                   *
                   * Using this function in any other way is effectively circumventing the admin
                   * system imposed by {AccessControl}.
                   * ====
                   */
                  function _setupRole(bytes32 role, address account) internal virtual {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Sets `adminRole` as ``role``'s admin role.
                   *
                   * Emits a {RoleAdminChanged} event.
                   */
                  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                      emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
                      _roles[role].adminRole = adminRole;
                  }
              
                  function _grantRole(bytes32 role, address account) private {
                      if (!hasRole(role, account)) {
                          _roles[role].members[account] = true;
                          emit RoleGranted(role, account, _msgSender());
                      }
                  }
              
                  function _revokeRole(bytes32 role, address account) private {
                      if (hasRole(role, account)) {
                          _roles[role].members[account] = false;
                          emit RoleRevoked(role, account, _msgSender());
                      }
                  }
              }
              
              // File: contracts/VestingMultiVault.sol
              
              pragma solidity ^0.8.0;
              
              
              
              
              
              /**
               * @title VestingMultiVault
               * @dev A token vesting contract that will release tokens gradually like a
               * standard equity vesting schedule, with a cliff and vesting period but no
               * arbitrary restrictions on the frequency of claims. Optionally has an initial
               * tranche claimable immediately after the cliff expires (in addition to any
               * amounts that would have vested up to that point but didn't due to a cliff).
               */
              contract VestingMultiVault is AccessControl {
                  using SafeMath for uint256;
                  using SafeERC20 for IERC20;
              
                  event Issued(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 amount,
                      uint256 start,
                      uint256 cliff,
                      uint256 duration
                  );
              
                  event Released(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 amount,
                      uint256 remaining
                  );
                  
                  event Revoked(
                      address indexed beneficiary,
                      uint256 indexed allocationId,
                      uint256 allocationAmount,
                      uint256 revokedAmount
                  );
              
                  struct Allocation {
                      uint256 start;
                      uint256 cliff;
                      uint256 duration;
                      uint256 total;
                      uint256 claimed;
                      uint256 initial;
                  }
              
                  // The token being vested.
                  IERC20 public immutable token;
              
                  // The amount unclaimed for an address, whether or not vested.
                  mapping(address => uint256) public pendingAmount;
              
                  // The allocations assigned to an address.
                  mapping(address => Allocation[]) public userAllocations;
              
                  // The precomputed hash of the "ISSUER" role.
                  bytes32 public constant ISSUER = keccak256("ISSUER");
              
                  /**
                   * @dev Creates a vesting contract that releases allocations of a token
                   * over an arbitrary time period with support for tranches and cliffs.
                   * @param _token The ERC-20 token to be vested
                   */
                  constructor(IERC20 _token) {
                      token = _token;
                      _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
                      _setupRole(ISSUER, msg.sender);
                  }
              
                  /**
                   * @dev Creates a new allocation for a beneficiary. Tokens are released
                   * linearly over time until a given number of seconds have passed since the
                   * start of the vesting schedule. Callable only by issuers.
                   * @param _beneficiary The address to which tokens will be released
                   * @param _amount The amount of the allocation (in wei)
                   * @param _startAt The unix timestamp at which the vesting may begin
                   * @param _cliff The number of seconds after _startAt before which no vesting occurs
                   * @param _duration The number of seconds after which the entire allocation is vested
                   * @param _initialPct The percentage of the allocation initially available (integer, 0-100)
                   */
                  function issue(
                      address _beneficiary,
                      uint256 _amount,
                      uint256 _startAt,
                      uint256 _cliff,
                      uint256 _duration,
                      uint256 _initialPct
                  ) public onlyRole(ISSUER) {
                      require(token.allowance(msg.sender, address(this)) >= _amount, "Token allowance not sufficient");
                      require(_beneficiary != address(0), "Cannot grant tokens to the zero address");
                      require(_cliff <= _duration, "Cliff must not exceed duration");
                      require(_initialPct <= 100, "Initial release percentage must be an integer 0 to 100 (inclusive)");
              
                      // Pull the number of tokens required for the allocation.
                      token.safeTransferFrom(msg.sender, address(this), _amount);
              
                      // Increase the total pending for the address.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].add(_amount);
              
                      // Push the new allocation into the stack.
                      userAllocations[_beneficiary].push(Allocation({
                          claimed:    0,
                          cliff:      _cliff,
                          duration:   _duration,
                          initial:    _amount.mul(_initialPct).div(100),
                          start:      _startAt,
                          total:      _amount
                      }));
                      
                      emit Issued(
                          _beneficiary,
                          userAllocations[_beneficiary].length - 1,
                          _amount,
                          _startAt,
                          _cliff,
                          _duration
                      );
                  }
                  
                  /**
                   * @dev Revokes an existing allocation. Any unclaimed tokens are recalled
                   * and sent to the caller. Callable only be issuers.
                   * @param _beneficiary The address whose allocation is to be revoked
                   * @param _id The allocation ID to revoke
                   */
                  function revoke(
                      address _beneficiary,
                      uint256 _id
                  ) public onlyRole(ISSUER) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      
                      // Calculate the remaining amount.
                      uint256 total = allocation.total;
                      uint256 remainder = total.sub(allocation.claimed);
              
                      // Update the total pending for the address.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].sub(remainder);
              
                      // Update the allocation to be claimed in full.
                      allocation.claimed = total;
                      
                      // Transfer the tokens vested 
                      token.safeTransfer(msg.sender, remainder);
                      emit Revoked(
                          _beneficiary,
                          _id,
                          total,
                          remainder
                      );
                  }
              
                  /**
                   * @dev Transfers vested tokens from an allocation to its beneficiary. Callable by anyone.
                   * @param _beneficiary The address that has vested tokens
                   * @param _id The vested allocation index
                   */
                  function release(
                      address _beneficiary,
                      uint256 _id
                  ) public {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
              
                      // Calculate the releasable amount.
                      uint256 amount = _releasableAmount(allocation);
                      require(amount > 0, "Nothing to release");
                      
                      // Add the amount to the allocation's total claimed.
                      allocation.claimed = allocation.claimed.add(amount);
              
                      // Subtract the amount from the beneficiary's total pending.
                      pendingAmount[_beneficiary] = pendingAmount[_beneficiary].sub(amount);
              
                      // Transfer the tokens to the beneficiary.
                      token.safeTransfer(_beneficiary, amount);
              
                      emit Released(
                          _beneficiary,
                          _id,
                          amount,
                          allocation.total.sub(allocation.claimed)
                      );
                  }
                  
                  /**
                   * @dev Transfers vested tokens from any number of allocations to their beneficiary. Callable by anyone. May be gas-intensive.
                   * @param _beneficiary The address that has vested tokens
                   * @param _ids The vested allocation indexes
                   */
                  function releaseMultiple(
                      address _beneficiary,
                      uint256[] calldata _ids
                  ) external {
                      for (uint256 i = 0; i < _ids.length; i++) {
                          release(_beneficiary, _ids[i]);
                      }
                  }
                  
                  /**
                   * @dev Gets the number of allocations issued for a given address.
                   * @param _beneficiary The address to check for allocations
                   */
                  function allocationCount(
                      address _beneficiary
                  ) public view returns (uint256 count) {
                      return userAllocations[_beneficiary].length;
                  }
                  
                  /**
                   * @dev Calculates the amount that has already vested but has not yet been released for a given address.
                   * @param _beneficiary Address to check
                   * @param _id The allocation index
                   */
                  function releasableAmount(
                      address _beneficiary,
                      uint256 _id
                  ) public view returns (uint256 amount) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      return _releasableAmount(allocation);
                  }
                  
                  /**
                   * @dev Gets the total releasable for a given address. Likely gas-intensive, not intended for contract use.
                   * @param _beneficiary Address to check
                   */
                  function totalReleasableAount(
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      for (uint256 i = 0; i < allocationCount(_beneficiary); i++) {
                          amount = amount.add(releasableAmount(_beneficiary, i));
                      }
                      return amount;
                  }
                  
                  /**
                   * @dev Calculates the amount that has vested to date.
                   * @param _beneficiary Address to check
                   * @param _id The allocation index
                   */
                  function vestedAmount(
                      address _beneficiary,
                      uint256 _id
                  ) public view returns (uint256) {
                      Allocation storage allocation = userAllocations[_beneficiary][_id];
                      return _vestedAmount(allocation);
                  }
                  
                  /**
                   * @dev Gets the total ever vested for a given address. Likely gas-intensive, not intended for contract use.
                   * @param _beneficiary Address to check
                   */
                  function totalVestedAount(
                      address _beneficiary
                  ) public view returns (uint256 amount) {
                      for (uint256 i = 0; i < allocationCount(_beneficiary); i++) {
                          amount = amount.add(vestedAmount(_beneficiary, i));
                      }
                      return amount;
                  }
              
                  /**
                   * @dev Calculates the amount that has already vested but hasn't been released yet.
                   * @param allocation Allocation to calculate against
                   */
                  function _releasableAmount(
                      Allocation storage allocation
                  ) internal view returns (uint256) {
                      return _vestedAmount(allocation).sub(allocation.claimed);
                  }
              
                  /**
                   * @dev Calculates the amount that has already vested.
                   * @param allocation Allocation to calculate against
                   */
                  function _vestedAmount(
                      Allocation storage allocation
                  ) internal view returns (uint256 amount) {
                      if (block.timestamp < allocation.start.add(allocation.cliff)) {
                          // Nothing is vested until after the start time + cliff length.
                          amount = 0;
                      } else if (block.timestamp >= allocation.start.add(allocation.duration)) {
                          // The entire amount has vested if the entire duration has elapsed.
                          amount = allocation.total;
                      } else {
                          // The initial tranche is available once the cliff expires, plus any portion of
                          // tokens which have otherwise become vested as of the current block's timestamp.
                          amount = allocation.initial.add(
                              allocation.total
                                  .sub(allocation.initial)
                                  .sub(amount)
                                  .mul(block.timestamp.sub(allocation.start))
                                  .div(allocation.duration)
                          );
                      }
                      
                      return amount;
                  }
              }

              File 3 of 4: SushiToken
              // Sources flattened with hardhat v2.3.0 https://hardhat.org
              
              // File contracts/OpenZeppelin/utils/Context.sol
              
              pragma solidity 0.6.12;
              
              /*
               * @dev Provides information about the current execution context, including the
               * sender of the transaction and its data. While these are generally available
               * via msg.sender and msg.data, they should not be accessed in such a direct
               * manner, since when dealing with GSN meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract Context {
                  function _msgSender() internal view virtual returns (address payable) {
                      return msg.sender;
                  }
              
                  function _msgData() internal view virtual returns (bytes memory) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              
              // File contracts/OpenZeppelin/GSN/Context.sol
              
              pragma solidity 0.6.12;
              
              
              // File contracts/OpenZeppelin/math/SafeMath.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations with added overflow
               * checks.
               *
               * Arithmetic operations in Solidity wrap on overflow. This can easily result
               * in bugs, because programmers usually assume that an overflow raises an
               * error, which is the standard behavior in high level programming languages.
               * `SafeMath` restores this intuition by reverting the transaction when an
               * operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      uint256 c = a + b;
                      if (c < a) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b > a) return (false, 0);
                      return (true, a - b);
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-contracts/pull/522
                      if (a == 0) return (true, 0);
                      uint256 c = a * b;
                      if (c / a != b) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a / b);
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a % b);
                  }
              
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a, "SafeMath: addition overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a, "SafeMath: subtraction overflow");
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (a == 0) return 0;
                      uint256 c = a * b;
                      require(c / a == b, "SafeMath: multiplication overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: division by zero");
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: modulo by zero");
                      return a % b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b <= a, errorMessage);
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryDiv}.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a % b;
                  }
              }
              
              
              // File contracts/OpenZeppelin/utils/Address.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              
              // File contracts/interfaces/IERC20.sol
              
              pragma solidity 0.6.12;
              
              interface IERC20 {
                  function totalSupply() external view returns (uint256);
                  function balanceOf(address account) external view returns (uint256);
                  function allowance(address owner, address spender) external view returns (uint256);
                  function approve(address spender, uint256 amount) external returns (bool);
                  function name() external view returns (string memory);
                  function symbol() external view returns (string memory);
                  function decimals() external view returns (uint8);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external;
              }
              
              
              // File contracts/Tokens/ERC20.sol
              
              pragma solidity 0.6.12;
              
              
              
              
              /**
               * @dev Implementation of the {IERC20} interface.
               *
               * This implementation is agnostic to the way tokens are created. This means
               * that a supply mechanism has to be added in a derived contract using {_mint}.
               * For a generic mechanism see {ERC20PresetMinterPauser}.
               *
               * TIP: For a detailed writeup see our guide
               * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
               * to implement supply mechanisms].
               *
               * We have followed general OpenZeppelin guidelines: functions revert instead
               * of returning `false` on failure. This behavior is nonetheless conventional
               * and does not conflict with the expectations of ERC20 applications.
               *
               * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
               * This allows applications to reconstruct the allowance for all accounts just
               * by listening to said events. Other implementations of the EIP may not emit
               * these events, as it isn't required by the specification.
               *
               * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
               * functions have been added to mitigate the well-known issues around setting
               * allowances. See {IERC20-approve}.
               */
              
              contract ERC20 is IERC20, Context {
                  using SafeMath for uint256;
                  using Address for address;
                  bytes32 public DOMAIN_SEPARATOR;
              
                  mapping (address => uint256) private _balances;
                  mapping(address => uint256) public nonces;
              
                  mapping (address => mapping (address => uint256)) private _allowances;
              
                  uint256 private _totalSupply;
              
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
                  bool private _initialized;
              
                  /**
                   * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                   * a default value of 18.
                   *
                   * To select a different value for {decimals}, use {_setupDecimals}.
                   *
                   * All three of these values are immutable: they can only be set once during
                   * construction.
                   */
                  function _initERC20(string memory name_, string memory symbol_) internal {
                      require(!_initialized, "ERC20: token has already been initialized!");
                      _name = name_;
                      _symbol = symbol_;
                      _decimals = 18;
                      uint256 chainId;
                      assembly {
                          chainId := chainid()
                      }
                      DOMAIN_SEPARATOR = keccak256(abi.encode(keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"), chainId, address(this)));
               
                      _initialized = true;
                  }
              
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view override returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view override returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @dev Returns the number of decimals used to get its user representation.
                   * For example, if `decimals` equals `2`, a balance of `505` tokens should
                   * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                   *
                   * Tokens usually opt for a value of 18, imitating the relationship between
                   * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                   * called.
                   *
                   * NOTE: This information is only used for _display_ purposes: it in
                   * no way affects any of the arithmetic of the contract, including
                   * {IERC20-balanceOf} and {IERC20-transfer}.
                   */
                  function decimals() public view override returns (uint8) {
                      return _decimals;
                  }
              
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view override returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view override returns (uint256) {
                      return _balances[account];
                  }
              
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `recipient` cannot be the zero address.
                   * - the caller must have a balance of at least `amount`.
                   */
                  function transfer(address recipient, uint256 amount) public virtual returns (bool) {
                      _transfer(_msgSender(), recipient, amount);
                      return true;
                  }
              
                  /**
                   * @dev See {IERC20-allowance}.
                   */
                  function allowance(address owner, address spender) public view virtual override returns (uint256) {
                      return _allowances[owner][spender];
                  }
              
                  /**
                   * @dev See {IERC20-approve}.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   */
                  function approve(address spender, uint256 amount) public virtual override returns (bool) {
                      _approve(_msgSender(), spender, amount);
                      return true;
                  }
              
                // See https://eips.ethereum.org/EIPS/eip-191
                  string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";
                  // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                  bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
              
                  /// @notice Approves `value` from `owner_` to be spend by `spender`.
                  /// @param owner_ Address of the owner.
                  /// @param spender The address of the spender that gets approved to draw from `owner_`.
                  /// @param value The maximum collective amount that `spender` can draw.
                  /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
                  function permit(
                      address owner_,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external override {
                      require(owner_ != address(0), "ERC20: Owner cannot be 0");
                      require(block.timestamp < deadline, "ERC20: Expired");
                      bytes32 digest =
                          keccak256(
                              abi.encodePacked(
                                  EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA,
                                  DOMAIN_SEPARATOR,
                                  keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))
                              )
                          );
                      address recoveredAddress = ecrecover(digest, v, r, s);
                      require(recoveredAddress == owner_, "ERC20: Invalid Signature");
                      _approve(_msgSender(), spender, value);
              
                  }
              
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Emits an {Approval} event indicating the updated allowance. This is not
                   * required by the EIP. See the note at the beginning of {ERC20};
                   *
                   * Requirements:
                   * - `sender` and `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   * - the caller must have allowance for ``sender``'s tokens of at least
                   * `amount`.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) public virtual returns (bool) {
                      _transfer(sender, recipient, amount);
                      _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                      return true;
                  }
              
                  /**
                   * @dev Atomically increases the allowance granted to `spender` by the caller.
                   *
                   * This is an alternative to {approve} that can be used as a mitigation for
                   * problems described in {IERC20-approve}.
                   *
                   * Emits an {Approval} event indicating the updated allowance.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   */
                  function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                      _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                      return true;
                  }
              
                  /**
                   * @dev Atomically decreases the allowance granted to `spender` by the caller.
                   *
                   * This is an alternative to {approve} that can be used as a mitigation for
                   * problems described in {IERC20-approve}.
                   *
                   * Emits an {Approval} event indicating the updated allowance.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   * - `spender` must have allowance for the caller of at least
                   * `subtractedValue`.
                   */
                  function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                      _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                      return true;
                  }
              
                  /**
                   * @dev Moves tokens `amount` from `sender` to `recipient`.
                   *
                   * This is internal function is equivalent to {transfer}, and can be used to
                   * e.g. implement automatic token fees, slashing mechanisms, etc.
                   *
                   * Emits a {Transfer} event.
                   *
                   * Requirements:
                   *
                   * - `sender` cannot be the zero address.
                   * - `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   */
                  function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                      require(sender != address(0), "ERC20: transfer from the zero address");
                      require(recipient != address(0), "ERC20: transfer to the zero address");
              
                      _beforeTokenTransfer(sender, recipient, amount);
              
                      _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                      _balances[recipient] = _balances[recipient].add(amount);
                      emit Transfer(sender, recipient, amount);
                  }
              
                  /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                   * the total supply.
                   *
                   * Emits a {Transfer} event with `from` set to the zero address.
                   *
                   * Requirements
                   *
                   * - `to` cannot be the zero address.
                   */
                  function _mint(address account, uint256 amount) internal virtual {
                      require(account != address(0), "ERC20: mint to the zero address");
              
                      _beforeTokenTransfer(address(0), account, amount);
              
                      _totalSupply = _totalSupply.add(amount);
                      _balances[account] = _balances[account].add(amount);
                      emit Transfer(address(0), account, amount);
                  }
              
                  /**
                   * @dev Destroys `amount` tokens from `account`, reducing the
                   * total supply.
                   *
                   * Emits a {Transfer} event with `to` set to the zero address.
                   *
                   * Requirements
                   *
                   * - `account` cannot be the zero address.
                   * - `account` must have at least `amount` tokens.
                   */
                  function _burn(address account, uint256 amount) internal virtual {
                      require(account != address(0), "ERC20: burn from the zero address");
              
                      _beforeTokenTransfer(account, address(0), amount);
              
                      _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                      _totalSupply = _totalSupply.sub(amount);
                      emit Transfer(account, address(0), amount);
                  }
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                   *
                   * This internal function is equivalent to `approve`, and can be used to
                   * e.g. set automatic allowances for certain subsystems, etc.
                   *
                   * Emits an {Approval} event.
                   *
                   * Requirements:
                   *
                   * - `owner` cannot be the zero address.
                   * - `spender` cannot be the zero address.
                   */
                  function _approve(address owner, address spender, uint256 amount) internal virtual {
                      require(owner != address(0), "ERC20: approve from the zero address");
                      require(spender != address(0), "ERC20: approve to the zero address");
              
                      _allowances[owner][spender] = amount;
                      emit Approval(owner, spender, amount);
                  }
              
                  /**
                   * @dev Sets {decimals} to a value other than the default one of 18.
                   *
                   * WARNING: This function should only be called from the constructor. Most
                   * applications that interact with token contracts will not expect
                   * {decimals} to ever change, and may work incorrectly if it does.
                   */
                  function _setupDecimals(uint8 decimals_) internal {
                      _decimals = decimals_;
                  }
              
                  /**
                   * @dev Hook that is called before any transfer of tokens. This includes
                   * minting and burning.
                   *
                   * Calling conditions:
                   *
                   * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                   * will be to transferred to `to`.
                   * - when `from` is zero, `amount` tokens will be minted for `to`.
                   * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                   * - `from` and `to` are never both zero.
                   *
                   * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                   */
                  function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
              }
              
              
              // File contracts/interfaces/IMisoToken.sol
              
              pragma solidity 0.6.12;
              
              interface IMisoToken {
                  function init(bytes calldata data) external payable;
                  function initToken( bytes calldata data ) external;
                  function tokenTemplate() external view returns (uint256);
              
              }
              
              
              // File contracts/OpenZeppelin/utils/EnumerableSet.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Library for managing
               * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
               * types.
               *
               * Sets have the following properties:
               *
               * - Elements are added, removed, and checked for existence in constant time
               * (O(1)).
               * - Elements are enumerated in O(n). No guarantees are made on the ordering.
               *
               * ```
               * contract Example {
               *     // Add the library methods
               *     using EnumerableSet for EnumerableSet.AddressSet;
               *
               *     // Declare a set state variable
               *     EnumerableSet.AddressSet private mySet;
               * }
               * ```
               *
               * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
               * and `uint256` (`UintSet`) are supported.
               */
              library EnumerableSet {
                  // To implement this library for multiple types with as little code
                  // repetition as possible, we write it in terms of a generic Set type with
                  // bytes32 values.
                  // The Set implementation uses private functions, and user-facing
                  // implementations (such as AddressSet) are just wrappers around the
                  // underlying Set.
                  // This means that we can only create new EnumerableSets for types that fit
                  // in bytes32.
              
                  struct Set {
                      // Storage of set values
                      bytes32[] _values;
              
                      // Position of the value in the `values` array, plus 1 because index 0
                      // means a value is not in the set.
                      mapping (bytes32 => uint256) _indexes;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function _add(Set storage set, bytes32 value) private returns (bool) {
                      if (!_contains(set, value)) {
                          set._values.push(value);
                          // The value is stored at length-1, but we add 1 to all indexes
                          // and use 0 as a sentinel value
                          set._indexes[value] = set._values.length;
                          return true;
                      } else {
                          return false;
                      }
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function _remove(Set storage set, bytes32 value) private returns (bool) {
                      // We read and store the value's index to prevent multiple reads from the same storage slot
                      uint256 valueIndex = set._indexes[value];
              
                      if (valueIndex != 0) { // Equivalent to contains(set, value)
                          // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                          // the array, and then remove the last element (sometimes called as 'swap and pop').
                          // This modifies the order of the array, as noted in {at}.
              
                          uint256 toDeleteIndex = valueIndex - 1;
                          uint256 lastIndex = set._values.length - 1;
              
                          // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                          // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
              
                          bytes32 lastvalue = set._values[lastIndex];
              
                          // Move the last value to the index where the value to delete is
                          set._values[toDeleteIndex] = lastvalue;
                          // Update the index for the moved value
                          set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
              
                          // Delete the slot where the moved value was stored
                          set._values.pop();
              
                          // Delete the index for the deleted slot
                          delete set._indexes[value];
              
                          return true;
                      } else {
                          return false;
                      }
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function _contains(Set storage set, bytes32 value) private view returns (bool) {
                      return set._indexes[value] != 0;
                  }
              
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function _length(Set storage set) private view returns (uint256) {
                      return set._values.length;
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function _at(Set storage set, uint256 index) private view returns (bytes32) {
                      require(set._values.length > index, "EnumerableSet: index out of bounds");
                      return set._values[index];
                  }
              
                  // Bytes32Set
              
                  struct Bytes32Set {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _add(set._inner, value);
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _remove(set._inner, value);
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
                      return _contains(set._inner, value);
                  }
              
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(Bytes32Set storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
                      return _at(set._inner, index);
                  }
              
                  // AddressSet
              
                  struct AddressSet {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(AddressSet storage set, address value) internal returns (bool) {
                      return _add(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(AddressSet storage set, address value) internal returns (bool) {
                      return _remove(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(AddressSet storage set, address value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(AddressSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(AddressSet storage set, uint256 index) internal view returns (address) {
                      return address(uint160(uint256(_at(set._inner, index))));
                  }
              
              
                  // UintSet
              
                  struct UintSet {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(UintSet storage set, uint256 value) internal returns (bool) {
                      return _add(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(UintSet storage set, uint256 value) internal returns (bool) {
                      return _remove(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(UintSet storage set, uint256 value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function length(UintSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(UintSet storage set, uint256 index) internal view returns (uint256) {
                      return uint256(_at(set._inner, index));
                  }
              }
              
              
              // File contracts/OpenZeppelin/access/AccessControl.sol
              
              pragma solidity 0.6.12;
              
              
              
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it.
               */
              abstract contract AccessControl is Context {
                  using EnumerableSet for EnumerableSet.AddressSet;
                  using Address for address;
              
                  struct RoleData {
                      EnumerableSet.AddressSet members;
                      bytes32 adminRole;
                  }
              
                  mapping (bytes32 => RoleData) private _roles;
              
                  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
              
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   *
                   * _Available since v3.1._
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
              
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call, an admin role
                   * bearer except when using {_setupRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) public view returns (bool) {
                      return _roles[role].members.contains(account);
                  }
              
                  /**
                   * @dev Returns the number of accounts that have `role`. Can be used
                   * together with {getRoleMember} to enumerate all bearers of a role.
                   */
                  function getRoleMemberCount(bytes32 role) public view returns (uint256) {
                      return _roles[role].members.length();
                  }
              
                  /**
                   * @dev Returns one of the accounts that have `role`. `index` must be a
                   * value between 0 and {getRoleMemberCount}, non-inclusive.
                   *
                   * Role bearers are not sorted in any particular way, and their ordering may
                   * change at any point.
                   *
                   * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
                   * you perform all queries on the same block. See the following
                   * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
                   * for more information.
                   */
                  function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
                      return _roles[role].members.at(index);
                  }
              
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) public view returns (bytes32) {
                      return _roles[role].adminRole;
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) public virtual {
                      require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
              
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) public virtual {
                      require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `account`.
                   */
                  function renounceRole(bytes32 role, address account) public virtual {
                      require(account == _msgSender(), "AccessControl: can only renounce roles for self");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event. Note that unlike {grantRole}, this function doesn't perform any
                   * checks on the calling account.
                   *
                   * [WARNING]
                   * ====
                   * This function should only be called from the constructor when setting
                   * up the initial roles for the system.
                   *
                   * Using this function in any other way is effectively circumventing the admin
                   * system imposed by {AccessControl}.
                   * ====
                   */
                  function _setupRole(bytes32 role, address account) internal virtual {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Sets `adminRole` as ``role``'s admin role.
                   *
                   * Emits a {RoleAdminChanged} event.
                   */
                  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                      emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
                      _roles[role].adminRole = adminRole;
                  }
              
                  function _grantRole(bytes32 role, address account) private {
                      if (_roles[role].members.add(account)) {
                          emit RoleGranted(role, account, _msgSender());
                      }
                  }
              
                  function _revokeRole(bytes32 role, address account) private {
                      if (_roles[role].members.remove(account)) {
                          emit RoleRevoked(role, account, _msgSender());
                      }
                  }
              }
              
              
              // File contracts/Tokens/SushiToken.sol
              
              pragma solidity 0.6.12;
              
              
              
              // ---------------------------------------------------------------------
              //
              // SushiToken with Governance.
              //
              // From the MISO Token Factory
              // Made for Sushi.com 
              // 
              // Enjoy. (c) Chef Gonpachi 2021 
              // <https://github.com/chefgonpachi/MISO/>
              //
              // ---------------------------------------------------------------------
              // SPDX-License-Identifier: GPL-3.0                        
              // ---------------------------------------------------------------------
              
              contract SushiToken is IMisoToken, AccessControl, ERC20 {
              
                  /// @notice Miso template id for the token factory.
                  /// @dev For different token types, this must be incremented.
                  uint256 public constant override tokenTemplate = 3;
              
                  bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
              
                  function initToken(string memory _name, string memory _symbol, address _owner, uint256 _initialSupply) public {
                      _initERC20(_name, _symbol);
                      _setupRole(DEFAULT_ADMIN_ROLE, _owner);
                      _setupRole(MINTER_ROLE, _owner);
                      _mint(msg.sender, _initialSupply);
              
                  }
              
                  function init(bytes calldata _data) external override payable {}
              
                  function initToken(
                      bytes calldata _data
                  ) public override {
                      (string memory _name,
                      string memory _symbol,
                      address _owner,
                      uint256 _initialSupply) = abi.decode(_data, (string, string, address, uint256));
              
                      initToken(_name,_symbol,_owner,_initialSupply);
                  }
              
                 /** 
                   * @dev Generates init data for Token Factory
                   * @param _name - Token name
                   * @param _symbol - Token symbol
                   * @param _owner - Contract owner
                   * @param _initialSupply Amount of tokens minted on creation
                */
                  function getInitData(
                      string calldata _name,
                      string calldata _symbol,
                      address _owner,
                      uint256 _initialSupply
                  )
                      external
                      pure
                      returns (bytes memory _data)
                  {
                      return abi.encode(_name, _symbol, _owner, _initialSupply);
                  }
              
              
                  /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).
                  function mint(address _to, uint256 _amount) public  {
                      require(hasRole(MINTER_ROLE, _msgSender()), "SushiToken: must have minter role to mint");
                      _mint(_to, _amount);
                      _moveDelegates(address(0), _delegates[_to], _amount);
                  }
              
                  // Copied and modified from YAM code:
                  // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol
                  // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol
                  // Which is copied and modified from COMPOUND:
                  // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol
              
                  /// @notice A record of each accounts delegate
                  mapping (address => address) internal _delegates;
              
                  /// @notice A checkpoint for marking number of votes from a given block
                  struct Checkpoint {
                      uint32 fromBlock;
                      uint256 votes;
                  }
              
                  /// @notice A record of votes checkpoints for each account, by index
                  mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
              
                  /// @notice The number of checkpoints for each account
                  mapping (address => uint32) public numCheckpoints;
              
                  /// @notice The EIP-712 typehash for the contract's domain
                  bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
              
                  /// @notice The EIP-712 typehash for the delegation struct used by the contract
                  bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
              
                  /// @notice A record of states for signing / validating signatures
                  mapping (address => uint) public sigNonces;
              
                    /// @notice An event thats emitted when an account changes its delegate
                  event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
              
                  /// @notice An event thats emitted when a delegate account's vote balance changes
                  event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
              
                  /**
                   * @notice Delegate votes from `msg.sender` to `delegatee`
                   * @param delegator The address to get delegatee for
                   */
                  function delegates(address delegator)
                      external
                      view
                      returns (address)
                  {
                      return _delegates[delegator];
                  }
              
                 /**
                  * @notice Delegate votes from `msg.sender` to `delegatee`
                  * @param delegatee The address to delegate votes to
                  */
                  function delegate(address delegatee) external {
                      return _delegate(msg.sender, delegatee);
                  }
              
                  /**
                   * @notice Delegates votes from signatory to `delegatee`
                   * @param delegatee The address to delegate votes to
                   * @param nonce The contract state required to match the signature
                   * @param expiry The time at which to expire the signature
                   * @param v The recovery byte of the signature
                   * @param r Half of the ECDSA signature pair
                   * @param s Half of the ECDSA signature pair
                   */
                  function delegateBySig(
                      address delegatee,
                      uint nonce,
                      uint expiry,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  )
                      external
                  {
                      bytes32 domainSeparator = keccak256(
                          abi.encode(
                              DOMAIN_TYPEHASH,
                              keccak256(bytes(name())),
                              getChainId(),
                              address(this)
                          )
                      );
              
                      bytes32 structHash = keccak256(
                          abi.encode(
                              DELEGATION_TYPEHASH,
                              delegatee,
                              nonce,
                              expiry
                          )
                      );
              
                      bytes32 digest = keccak256(
                          abi.encodePacked(
                              "\x19\x01",
                              domainSeparator,
                              structHash
                          )
                      );
              
                      address signatory = ecrecover(digest, v, r, s);
                      require(signatory != address(0), "SUSHI::delegateBySig: invalid signature");
                      require(nonce == sigNonces[signatory]++, "SUSHI::delegateBySig: invalid nonce");
                      require(now <= expiry, "SUSHI::delegateBySig: signature expired");
                      return _delegate(signatory, delegatee);
                  }
              
                  /**
                   * @notice Gets the current votes balance for `account`
                   * @param account The address to get votes balance
                   * @return The number of current votes for `account`
                   */
                  function getCurrentVotes(address account)
                      external
                      view
                      returns (uint256)
                  {
                      uint32 nCheckpoints = numCheckpoints[account];
                      return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
                  }
              
                  /**
                   * @notice Determine the prior number of votes for an account as of a block number
                   * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
                   * @param account The address of the account to check
                   * @param blockNumber The block number to get the vote balance at
                   * @return The number of votes the account had as of the given block
                   */
                  function getPriorVotes(address account, uint blockNumber)
                      external
                      view
                      returns (uint256)
                  {
                      require(blockNumber < block.number, "SUSHI::getPriorVotes: not yet determined");
              
                      uint32 nCheckpoints = numCheckpoints[account];
                      if (nCheckpoints == 0) {
                          return 0;
                      }
              
                      // First check most recent balance
                      if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                          return checkpoints[account][nCheckpoints - 1].votes;
                      }
              
                      // Next check implicit zero balance
                      if (checkpoints[account][0].fromBlock > blockNumber) {
                          return 0;
                      }
              
                      uint32 lower = 0;
                      uint32 upper = nCheckpoints - 1;
                      while (upper > lower) {
                          uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                          Checkpoint memory cp = checkpoints[account][center];
                          if (cp.fromBlock == blockNumber) {
                              return cp.votes;
                          } else if (cp.fromBlock < blockNumber) {
                              lower = center;
                          } else {
                              upper = center - 1;
                          }
                      }
                      return checkpoints[account][lower].votes;
                  }
              
                  function _delegate(address delegator, address delegatee)
                      internal
                  {
                      address currentDelegate = _delegates[delegator];
                      uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SUSHIs (not scaled);
                      _delegates[delegator] = delegatee;
              
                      emit DelegateChanged(delegator, currentDelegate, delegatee);
              
                      _moveDelegates(currentDelegate, delegatee, delegatorBalance);
                  }
              
                  function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {
                      if (srcRep != dstRep && amount > 0) {
                          if (srcRep != address(0)) {
                              // decrease old representative
                              uint32 srcRepNum = numCheckpoints[srcRep];
                              uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                              uint256 srcRepNew = srcRepOld.sub(amount);
                              _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                          }
              
                          if (dstRep != address(0)) {
                              // increase new representative
                              uint32 dstRepNum = numCheckpoints[dstRep];
                              uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                              uint256 dstRepNew = dstRepOld.add(amount);
                              _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                          }
                      }
                  }
              
                  function _writeCheckpoint(
                      address delegatee,
                      uint32 nCheckpoints,
                      uint256 oldVotes,
                      uint256 newVotes
                  )
                      internal
                  {
                      uint32 blockNumber = safe32(block.number, "SUSHI::_writeCheckpoint: block number exceeds 32 bits");
              
                      if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
                          checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
                      } else {
                          checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                          numCheckpoints[delegatee] = nCheckpoints + 1;
                      }
              
                      emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
                  }
              
                  function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
                      require(n < 2**32, errorMessage);
                      return uint32(n);
                  }
              
                  function getChainId() internal pure returns (uint) {
                      uint256 chainId;
                      assembly { chainId := chainid() }
                      return chainId;
                  }
              }

              File 4 of 4: SushiToken
              // Sources flattened with hardhat v2.3.0 https://hardhat.org
              
              // File contracts/OpenZeppelin/utils/Context.sol
              
              pragma solidity 0.6.12;
              
              /*
               * @dev Provides information about the current execution context, including the
               * sender of the transaction and its data. While these are generally available
               * via msg.sender and msg.data, they should not be accessed in such a direct
               * manner, since when dealing with GSN meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract Context {
                  function _msgSender() internal view virtual returns (address payable) {
                      return msg.sender;
                  }
              
                  function _msgData() internal view virtual returns (bytes memory) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              
              
              // File contracts/OpenZeppelin/GSN/Context.sol
              
              pragma solidity 0.6.12;
              
              
              // File contracts/OpenZeppelin/math/SafeMath.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Wrappers over Solidity's arithmetic operations with added overflow
               * checks.
               *
               * Arithmetic operations in Solidity wrap on overflow. This can easily result
               * in bugs, because programmers usually assume that an overflow raises an
               * error, which is the standard behavior in high level programming languages.
               * `SafeMath` restores this intuition by reverting the transaction when an
               * operation overflows.
               *
               * Using this library instead of the unchecked operations eliminates an entire
               * class of bugs, so it's recommended to use it always.
               */
              library SafeMath {
                  /**
                   * @dev Returns the addition of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      uint256 c = a + b;
                      if (c < a) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b > a) return (false, 0);
                      return (true, a - b);
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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-contracts/pull/522
                      if (a == 0) return (true, 0);
                      uint256 c = a * b;
                      if (c / a != b) return (false, 0);
                      return (true, c);
                  }
              
                  /**
                   * @dev Returns the division of two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a / b);
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                   *
                   * _Available since v3.4._
                   */
                  function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                      if (b == 0) return (false, 0);
                      return (true, a % b);
                  }
              
                  /**
                   * @dev Returns the addition of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `+` operator.
                   *
                   * Requirements:
                   *
                   * - Addition cannot overflow.
                   */
                  function add(uint256 a, uint256 b) internal pure returns (uint256) {
                      uint256 c = a + b;
                      require(c >= a, "SafeMath: addition overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting on
                   * overflow (when the result is negative).
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b <= a, "SafeMath: subtraction overflow");
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the multiplication of two unsigned integers, reverting on
                   * overflow.
                   *
                   * Counterpart to Solidity's `*` operator.
                   *
                   * Requirements:
                   *
                   * - Multiplication cannot overflow.
                   */
                  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                      if (a == 0) return 0;
                      uint256 c = a * b;
                      require(c / a == b, "SafeMath: multiplication overflow");
                      return c;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting on
                   * division by zero. The result is rounded towards zero.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: division by zero");
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting when dividing by zero.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                      require(b > 0, "SafeMath: modulo by zero");
                      return a % b;
                  }
              
                  /**
                   * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                   * overflow (when the result is negative).
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {trySub}.
                   *
                   * Counterpart to Solidity's `-` operator.
                   *
                   * Requirements:
                   *
                   * - Subtraction cannot overflow.
                   */
                  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b <= a, errorMessage);
                      return a - b;
                  }
              
                  /**
                   * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                   * division by zero. The result is rounded towards zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryDiv}.
                   *
                   * Counterpart to Solidity's `/` operator. Note: this function uses a
                   * `revert` opcode (which leaves remaining gas untouched) while Solidity
                   * uses an invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a / b;
                  }
              
                  /**
                   * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                   * reverting with custom message when dividing by zero.
                   *
                   * CAUTION: This function is deprecated because it requires allocating memory for the error
                   * message unnecessarily. For custom revert reasons use {tryMod}.
                   *
                   * Counterpart to Solidity's `%` operator. This function uses a `revert`
                   * opcode (which leaves remaining gas untouched) while Solidity uses an
                   * invalid opcode to revert (consuming all remaining gas).
                   *
                   * Requirements:
                   *
                   * - The divisor cannot be zero.
                   */
                  function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                      require(b > 0, errorMessage);
                      return a % b;
                  }
              }
              
              
              // File contracts/OpenZeppelin/utils/Address.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Collection of functions related to the address type
               */
              library Address {
                  /**
                   * @dev Returns true if `account` is a contract.
                   *
                   * [IMPORTANT]
                   * ====
                   * It is unsafe to assume that an address for which this function returns
                   * false is an externally-owned account (EOA) and not a contract.
                   *
                   * Among others, `isContract` will return false for the following
                   * types of addresses:
                   *
                   *  - an externally-owned account
                   *  - a contract in construction
                   *  - an address where a contract will be created
                   *  - an address where a contract lived, but was destroyed
                   * ====
                   */
                  function isContract(address account) internal view returns (bool) {
                      // This method relies on extcodesize, which returns 0 for contracts in
                      // construction, since the code is only stored at the end of the
                      // constructor execution.
              
                      uint256 size;
                      // solhint-disable-next-line no-inline-assembly
                      assembly { size := extcodesize(account) }
                      return size > 0;
                  }
              
                  /**
                   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                   * `recipient`, forwarding all available gas and reverting on errors.
                   *
                   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                   * of certain opcodes, possibly making contracts go over the 2300 gas limit
                   * imposed by `transfer`, making them unable to receive funds via
                   * `transfer`. {sendValue} removes this limitation.
                   *
                   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                   *
                   * IMPORTANT: because control is transferred to `recipient`, care must be
                   * taken to not create reentrancy vulnerabilities. Consider using
                   * {ReentrancyGuard} or the
                   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                   */
                  function sendValue(address payable recipient, uint256 amount) internal {
                      require(address(this).balance >= amount, "Address: insufficient balance");
              
                      // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                      (bool success, ) = recipient.call{ value: amount }("");
                      require(success, "Address: unable to send value, recipient may have reverted");
                  }
              
                  /**
                   * @dev Performs a Solidity function call using a low level `call`. A
                   * plain`call` is an unsafe replacement for a function call: use this
                   * function instead.
                   *
                   * If `target` reverts with a revert reason, it is bubbled up by this
                   * function (like regular Solidity function calls).
                   *
                   * Returns the raw returned data. To convert to the expected return value,
                   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                   *
                   * Requirements:
                   *
                   * - `target` must be a contract.
                   * - calling `target` with `data` must not revert.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                   * `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, 0, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but also transferring `value` wei to `target`.
                   *
                   * Requirements:
                   *
                   * - the calling contract must have an ETH balance of at least `value`.
                   * - the called Solidity function must be `payable`.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                      return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                   * with `errorMessage` as a fallback revert reason when `target` reverts.
                   *
                   * _Available since v3.1._
                   */
                  function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                      require(address(this).balance >= value, "Address: insufficient balance for call");
                      require(isContract(target), "Address: call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.call{ value: value }(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                      return functionStaticCall(target, data, "Address: low-level static call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a static call.
                   *
                   * _Available since v3.3._
                   */
                  function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                      require(isContract(target), "Address: static call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.staticcall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                      return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                  }
              
                  /**
                   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                   * but performing a delegate call.
                   *
                   * _Available since v3.4._
                   */
                  function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                      require(isContract(target), "Address: delegate call to non-contract");
              
                      // solhint-disable-next-line avoid-low-level-calls
                      (bool success, bytes memory returndata) = target.delegatecall(data);
                      return _verifyCallResult(success, returndata, errorMessage);
                  }
              
                  function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                      if (success) {
                          return returndata;
                      } else {
                          // Look for revert reason and bubble it up if present
                          if (returndata.length > 0) {
                              // The easiest way to bubble the revert reason is using memory via assembly
              
                              // solhint-disable-next-line no-inline-assembly
                              assembly {
                                  let returndata_size := mload(returndata)
                                  revert(add(32, returndata), returndata_size)
                              }
                          } else {
                              revert(errorMessage);
                          }
                      }
                  }
              }
              
              
              // File contracts/interfaces/IERC20.sol
              
              pragma solidity 0.6.12;
              
              interface IERC20 {
                  function totalSupply() external view returns (uint256);
                  function balanceOf(address account) external view returns (uint256);
                  function allowance(address owner, address spender) external view returns (uint256);
                  function approve(address spender, uint256 amount) external returns (bool);
                  function name() external view returns (string memory);
                  function symbol() external view returns (string memory);
                  function decimals() external view returns (uint8);
              
                  event Transfer(address indexed from, address indexed to, uint256 value);
                  event Approval(address indexed owner, address indexed spender, uint256 value);
              
                  function permit(
                      address owner,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external;
              }
              
              
              // File contracts/Tokens/ERC20.sol
              
              pragma solidity 0.6.12;
              
              
              
              
              /**
               * @dev Implementation of the {IERC20} interface.
               *
               * This implementation is agnostic to the way tokens are created. This means
               * that a supply mechanism has to be added in a derived contract using {_mint}.
               * For a generic mechanism see {ERC20PresetMinterPauser}.
               *
               * TIP: For a detailed writeup see our guide
               * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
               * to implement supply mechanisms].
               *
               * We have followed general OpenZeppelin guidelines: functions revert instead
               * of returning `false` on failure. This behavior is nonetheless conventional
               * and does not conflict with the expectations of ERC20 applications.
               *
               * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
               * This allows applications to reconstruct the allowance for all accounts just
               * by listening to said events. Other implementations of the EIP may not emit
               * these events, as it isn't required by the specification.
               *
               * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
               * functions have been added to mitigate the well-known issues around setting
               * allowances. See {IERC20-approve}.
               */
              
              contract ERC20 is IERC20, Context {
                  using SafeMath for uint256;
                  using Address for address;
                  bytes32 public DOMAIN_SEPARATOR;
              
                  mapping (address => uint256) private _balances;
                  mapping(address => uint256) public nonces;
              
                  mapping (address => mapping (address => uint256)) private _allowances;
              
                  uint256 private _totalSupply;
              
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
                  bool private _initialized;
              
                  /**
                   * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                   * a default value of 18.
                   *
                   * To select a different value for {decimals}, use {_setupDecimals}.
                   *
                   * All three of these values are immutable: they can only be set once during
                   * construction.
                   */
                  function _initERC20(string memory name_, string memory symbol_) internal {
                      require(!_initialized, "ERC20: token has already been initialized!");
                      _name = name_;
                      _symbol = symbol_;
                      _decimals = 18;
                      uint256 chainId;
                      assembly {
                          chainId := chainid()
                      }
                      DOMAIN_SEPARATOR = keccak256(abi.encode(keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"), chainId, address(this)));
               
                      _initialized = true;
                  }
              
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view override returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view override returns (string memory) {
                      return _symbol;
                  }
              
                  /**
                   * @dev Returns the number of decimals used to get its user representation.
                   * For example, if `decimals` equals `2`, a balance of `505` tokens should
                   * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                   *
                   * Tokens usually opt for a value of 18, imitating the relationship between
                   * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                   * called.
                   *
                   * NOTE: This information is only used for _display_ purposes: it in
                   * no way affects any of the arithmetic of the contract, including
                   * {IERC20-balanceOf} and {IERC20-transfer}.
                   */
                  function decimals() public view override returns (uint8) {
                      return _decimals;
                  }
              
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view override returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view override returns (uint256) {
                      return _balances[account];
                  }
              
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `recipient` cannot be the zero address.
                   * - the caller must have a balance of at least `amount`.
                   */
                  function transfer(address recipient, uint256 amount) public virtual returns (bool) {
                      _transfer(_msgSender(), recipient, amount);
                      return true;
                  }
              
                  /**
                   * @dev See {IERC20-allowance}.
                   */
                  function allowance(address owner, address spender) public view virtual override returns (uint256) {
                      return _allowances[owner][spender];
                  }
              
                  /**
                   * @dev See {IERC20-approve}.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   */
                  function approve(address spender, uint256 amount) public virtual override returns (bool) {
                      _approve(_msgSender(), spender, amount);
                      return true;
                  }
              
                // See https://eips.ethereum.org/EIPS/eip-191
                  string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";
                  // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
                  bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
              
                  /// @notice Approves `value` from `owner_` to be spend by `spender`.
                  /// @param owner_ Address of the owner.
                  /// @param spender The address of the spender that gets approved to draw from `owner_`.
                  /// @param value The maximum collective amount that `spender` can draw.
                  /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
                  function permit(
                      address owner_,
                      address spender,
                      uint256 value,
                      uint256 deadline,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  ) external override {
                      require(owner_ != address(0), "ERC20: Owner cannot be 0");
                      require(block.timestamp < deadline, "ERC20: Expired");
                      bytes32 digest =
                          keccak256(
                              abi.encodePacked(
                                  EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA,
                                  DOMAIN_SEPARATOR,
                                  keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))
                              )
                          );
                      address recoveredAddress = ecrecover(digest, v, r, s);
                      require(recoveredAddress == owner_, "ERC20: Invalid Signature");
                      _approve(_msgSender(), spender, value);
              
                  }
              
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Emits an {Approval} event indicating the updated allowance. This is not
                   * required by the EIP. See the note at the beginning of {ERC20};
                   *
                   * Requirements:
                   * - `sender` and `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   * - the caller must have allowance for ``sender``'s tokens of at least
                   * `amount`.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) public virtual returns (bool) {
                      _transfer(sender, recipient, amount);
                      _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                      return true;
                  }
              
                  /**
                   * @dev Atomically increases the allowance granted to `spender` by the caller.
                   *
                   * This is an alternative to {approve} that can be used as a mitigation for
                   * problems described in {IERC20-approve}.
                   *
                   * Emits an {Approval} event indicating the updated allowance.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   */
                  function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                      _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                      return true;
                  }
              
                  /**
                   * @dev Atomically decreases the allowance granted to `spender` by the caller.
                   *
                   * This is an alternative to {approve} that can be used as a mitigation for
                   * problems described in {IERC20-approve}.
                   *
                   * Emits an {Approval} event indicating the updated allowance.
                   *
                   * Requirements:
                   *
                   * - `spender` cannot be the zero address.
                   * - `spender` must have allowance for the caller of at least
                   * `subtractedValue`.
                   */
                  function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                      _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                      return true;
                  }
              
                  /**
                   * @dev Moves tokens `amount` from `sender` to `recipient`.
                   *
                   * This is internal function is equivalent to {transfer}, and can be used to
                   * e.g. implement automatic token fees, slashing mechanisms, etc.
                   *
                   * Emits a {Transfer} event.
                   *
                   * Requirements:
                   *
                   * - `sender` cannot be the zero address.
                   * - `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   */
                  function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                      require(sender != address(0), "ERC20: transfer from the zero address");
                      require(recipient != address(0), "ERC20: transfer to the zero address");
              
                      _beforeTokenTransfer(sender, recipient, amount);
              
                      _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                      _balances[recipient] = _balances[recipient].add(amount);
                      emit Transfer(sender, recipient, amount);
                  }
              
                  /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                   * the total supply.
                   *
                   * Emits a {Transfer} event with `from` set to the zero address.
                   *
                   * Requirements
                   *
                   * - `to` cannot be the zero address.
                   */
                  function _mint(address account, uint256 amount) internal virtual {
                      require(account != address(0), "ERC20: mint to the zero address");
              
                      _beforeTokenTransfer(address(0), account, amount);
              
                      _totalSupply = _totalSupply.add(amount);
                      _balances[account] = _balances[account].add(amount);
                      emit Transfer(address(0), account, amount);
                  }
              
                  /**
                   * @dev Destroys `amount` tokens from `account`, reducing the
                   * total supply.
                   *
                   * Emits a {Transfer} event with `to` set to the zero address.
                   *
                   * Requirements
                   *
                   * - `account` cannot be the zero address.
                   * - `account` must have at least `amount` tokens.
                   */
                  function _burn(address account, uint256 amount) internal virtual {
                      require(account != address(0), "ERC20: burn from the zero address");
              
                      _beforeTokenTransfer(account, address(0), amount);
              
                      _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                      _totalSupply = _totalSupply.sub(amount);
                      emit Transfer(account, address(0), amount);
                  }
              
                  /**
                   * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                   *
                   * This internal function is equivalent to `approve`, and can be used to
                   * e.g. set automatic allowances for certain subsystems, etc.
                   *
                   * Emits an {Approval} event.
                   *
                   * Requirements:
                   *
                   * - `owner` cannot be the zero address.
                   * - `spender` cannot be the zero address.
                   */
                  function _approve(address owner, address spender, uint256 amount) internal virtual {
                      require(owner != address(0), "ERC20: approve from the zero address");
                      require(spender != address(0), "ERC20: approve to the zero address");
              
                      _allowances[owner][spender] = amount;
                      emit Approval(owner, spender, amount);
                  }
              
                  /**
                   * @dev Sets {decimals} to a value other than the default one of 18.
                   *
                   * WARNING: This function should only be called from the constructor. Most
                   * applications that interact with token contracts will not expect
                   * {decimals} to ever change, and may work incorrectly if it does.
                   */
                  function _setupDecimals(uint8 decimals_) internal {
                      _decimals = decimals_;
                  }
              
                  /**
                   * @dev Hook that is called before any transfer of tokens. This includes
                   * minting and burning.
                   *
                   * Calling conditions:
                   *
                   * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                   * will be to transferred to `to`.
                   * - when `from` is zero, `amount` tokens will be minted for `to`.
                   * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                   * - `from` and `to` are never both zero.
                   *
                   * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                   */
                  function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
              }
              
              
              // File contracts/interfaces/IMisoToken.sol
              
              pragma solidity 0.6.12;
              
              interface IMisoToken {
                  function init(bytes calldata data) external payable;
                  function initToken( bytes calldata data ) external;
                  function tokenTemplate() external view returns (uint256);
              
              }
              
              
              // File contracts/OpenZeppelin/utils/EnumerableSet.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Library for managing
               * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
               * types.
               *
               * Sets have the following properties:
               *
               * - Elements are added, removed, and checked for existence in constant time
               * (O(1)).
               * - Elements are enumerated in O(n). No guarantees are made on the ordering.
               *
               * ```
               * contract Example {
               *     // Add the library methods
               *     using EnumerableSet for EnumerableSet.AddressSet;
               *
               *     // Declare a set state variable
               *     EnumerableSet.AddressSet private mySet;
               * }
               * ```
               *
               * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
               * and `uint256` (`UintSet`) are supported.
               */
              library EnumerableSet {
                  // To implement this library for multiple types with as little code
                  // repetition as possible, we write it in terms of a generic Set type with
                  // bytes32 values.
                  // The Set implementation uses private functions, and user-facing
                  // implementations (such as AddressSet) are just wrappers around the
                  // underlying Set.
                  // This means that we can only create new EnumerableSets for types that fit
                  // in bytes32.
              
                  struct Set {
                      // Storage of set values
                      bytes32[] _values;
              
                      // Position of the value in the `values` array, plus 1 because index 0
                      // means a value is not in the set.
                      mapping (bytes32 => uint256) _indexes;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function _add(Set storage set, bytes32 value) private returns (bool) {
                      if (!_contains(set, value)) {
                          set._values.push(value);
                          // The value is stored at length-1, but we add 1 to all indexes
                          // and use 0 as a sentinel value
                          set._indexes[value] = set._values.length;
                          return true;
                      } else {
                          return false;
                      }
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function _remove(Set storage set, bytes32 value) private returns (bool) {
                      // We read and store the value's index to prevent multiple reads from the same storage slot
                      uint256 valueIndex = set._indexes[value];
              
                      if (valueIndex != 0) { // Equivalent to contains(set, value)
                          // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                          // the array, and then remove the last element (sometimes called as 'swap and pop').
                          // This modifies the order of the array, as noted in {at}.
              
                          uint256 toDeleteIndex = valueIndex - 1;
                          uint256 lastIndex = set._values.length - 1;
              
                          // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                          // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
              
                          bytes32 lastvalue = set._values[lastIndex];
              
                          // Move the last value to the index where the value to delete is
                          set._values[toDeleteIndex] = lastvalue;
                          // Update the index for the moved value
                          set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
              
                          // Delete the slot where the moved value was stored
                          set._values.pop();
              
                          // Delete the index for the deleted slot
                          delete set._indexes[value];
              
                          return true;
                      } else {
                          return false;
                      }
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function _contains(Set storage set, bytes32 value) private view returns (bool) {
                      return set._indexes[value] != 0;
                  }
              
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function _length(Set storage set) private view returns (uint256) {
                      return set._values.length;
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function _at(Set storage set, uint256 index) private view returns (bytes32) {
                      require(set._values.length > index, "EnumerableSet: index out of bounds");
                      return set._values[index];
                  }
              
                  // Bytes32Set
              
                  struct Bytes32Set {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _add(set._inner, value);
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
                      return _remove(set._inner, value);
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
                      return _contains(set._inner, value);
                  }
              
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(Bytes32Set storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
                      return _at(set._inner, index);
                  }
              
                  // AddressSet
              
                  struct AddressSet {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(AddressSet storage set, address value) internal returns (bool) {
                      return _add(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(AddressSet storage set, address value) internal returns (bool) {
                      return _remove(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(AddressSet storage set, address value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(uint256(uint160(value))));
                  }
              
                  /**
                   * @dev Returns the number of values in the set. O(1).
                   */
                  function length(AddressSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(AddressSet storage set, uint256 index) internal view returns (address) {
                      return address(uint160(uint256(_at(set._inner, index))));
                  }
              
              
                  // UintSet
              
                  struct UintSet {
                      Set _inner;
                  }
              
                  /**
                   * @dev Add a value to a set. O(1).
                   *
                   * Returns true if the value was added to the set, that is if it was not
                   * already present.
                   */
                  function add(UintSet storage set, uint256 value) internal returns (bool) {
                      return _add(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Removes a value from a set. O(1).
                   *
                   * Returns true if the value was removed from the set, that is if it was
                   * present.
                   */
                  function remove(UintSet storage set, uint256 value) internal returns (bool) {
                      return _remove(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Returns true if the value is in the set. O(1).
                   */
                  function contains(UintSet storage set, uint256 value) internal view returns (bool) {
                      return _contains(set._inner, bytes32(value));
                  }
              
                  /**
                   * @dev Returns the number of values on the set. O(1).
                   */
                  function length(UintSet storage set) internal view returns (uint256) {
                      return _length(set._inner);
                  }
              
                 /**
                  * @dev Returns the value stored at position `index` in the set. O(1).
                  *
                  * Note that there are no guarantees on the ordering of values inside the
                  * array, and it may change when more values are added or removed.
                  *
                  * Requirements:
                  *
                  * - `index` must be strictly less than {length}.
                  */
                  function at(UintSet storage set, uint256 index) internal view returns (uint256) {
                      return uint256(_at(set._inner, index));
                  }
              }
              
              
              // File contracts/OpenZeppelin/access/AccessControl.sol
              
              pragma solidity 0.6.12;
              
              
              
              /**
               * @dev Contract module that allows children to implement role-based access
               * control mechanisms.
               *
               * Roles are referred to by their `bytes32` identifier. These should be exposed
               * in the external API and be unique. The best way to achieve this is by
               * using `public constant` hash digests:
               *
               * ```
               * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
               * ```
               *
               * Roles can be used to represent a set of permissions. To restrict access to a
               * function call, use {hasRole}:
               *
               * ```
               * function foo() public {
               *     require(hasRole(MY_ROLE, msg.sender));
               *     ...
               * }
               * ```
               *
               * Roles can be granted and revoked dynamically via the {grantRole} and
               * {revokeRole} functions. Each role has an associated admin role, and only
               * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
               *
               * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
               * that only accounts with this role will be able to grant or revoke other
               * roles. More complex role relationships can be created by using
               * {_setRoleAdmin}.
               *
               * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
               * grant and revoke this role. Extra precautions should be taken to secure
               * accounts that have been granted it.
               */
              abstract contract AccessControl is Context {
                  using EnumerableSet for EnumerableSet.AddressSet;
                  using Address for address;
              
                  struct RoleData {
                      EnumerableSet.AddressSet members;
                      bytes32 adminRole;
                  }
              
                  mapping (bytes32 => RoleData) private _roles;
              
                  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
              
                  /**
                   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
                   *
                   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
                   * {RoleAdminChanged} not being emitted signaling this.
                   *
                   * _Available since v3.1._
                   */
                  event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
              
                  /**
                   * @dev Emitted when `account` is granted `role`.
                   *
                   * `sender` is the account that originated the contract call, an admin role
                   * bearer except when using {_setupRole}.
                   */
                  event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Emitted when `account` is revoked `role`.
                   *
                   * `sender` is the account that originated the contract call:
                   *   - if using `revokeRole`, it is the admin role bearer
                   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
                   */
                  event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
              
                  /**
                   * @dev Returns `true` if `account` has been granted `role`.
                   */
                  function hasRole(bytes32 role, address account) public view returns (bool) {
                      return _roles[role].members.contains(account);
                  }
              
                  /**
                   * @dev Returns the number of accounts that have `role`. Can be used
                   * together with {getRoleMember} to enumerate all bearers of a role.
                   */
                  function getRoleMemberCount(bytes32 role) public view returns (uint256) {
                      return _roles[role].members.length();
                  }
              
                  /**
                   * @dev Returns one of the accounts that have `role`. `index` must be a
                   * value between 0 and {getRoleMemberCount}, non-inclusive.
                   *
                   * Role bearers are not sorted in any particular way, and their ordering may
                   * change at any point.
                   *
                   * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
                   * you perform all queries on the same block. See the following
                   * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
                   * for more information.
                   */
                  function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
                      return _roles[role].members.at(index);
                  }
              
                  /**
                   * @dev Returns the admin role that controls `role`. See {grantRole} and
                   * {revokeRole}.
                   *
                   * To change a role's admin, use {_setRoleAdmin}.
                   */
                  function getRoleAdmin(bytes32 role) public view returns (bytes32) {
                      return _roles[role].adminRole;
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function grantRole(bytes32 role, address account) public virtual {
                      require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
              
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from `account`.
                   *
                   * If `account` had been granted `role`, emits a {RoleRevoked} event.
                   *
                   * Requirements:
                   *
                   * - the caller must have ``role``'s admin role.
                   */
                  function revokeRole(bytes32 role, address account) public virtual {
                      require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Revokes `role` from the calling account.
                   *
                   * Roles are often managed via {grantRole} and {revokeRole}: this function's
                   * purpose is to provide a mechanism for accounts to lose their privileges
                   * if they are compromised (such as when a trusted device is misplaced).
                   *
                   * If the calling account had been granted `role`, emits a {RoleRevoked}
                   * event.
                   *
                   * Requirements:
                   *
                   * - the caller must be `account`.
                   */
                  function renounceRole(bytes32 role, address account) public virtual {
                      require(account == _msgSender(), "AccessControl: can only renounce roles for self");
              
                      _revokeRole(role, account);
                  }
              
                  /**
                   * @dev Grants `role` to `account`.
                   *
                   * If `account` had not been already granted `role`, emits a {RoleGranted}
                   * event. Note that unlike {grantRole}, this function doesn't perform any
                   * checks on the calling account.
                   *
                   * [WARNING]
                   * ====
                   * This function should only be called from the constructor when setting
                   * up the initial roles for the system.
                   *
                   * Using this function in any other way is effectively circumventing the admin
                   * system imposed by {AccessControl}.
                   * ====
                   */
                  function _setupRole(bytes32 role, address account) internal virtual {
                      _grantRole(role, account);
                  }
              
                  /**
                   * @dev Sets `adminRole` as ``role``'s admin role.
                   *
                   * Emits a {RoleAdminChanged} event.
                   */
                  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                      emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
                      _roles[role].adminRole = adminRole;
                  }
              
                  function _grantRole(bytes32 role, address account) private {
                      if (_roles[role].members.add(account)) {
                          emit RoleGranted(role, account, _msgSender());
                      }
                  }
              
                  function _revokeRole(bytes32 role, address account) private {
                      if (_roles[role].members.remove(account)) {
                          emit RoleRevoked(role, account, _msgSender());
                      }
                  }
              }
              
              
              // File contracts/Tokens/SushiToken.sol
              
              pragma solidity 0.6.12;
              
              
              
              // ---------------------------------------------------------------------
              //
              // SushiToken with Governance.
              //
              // From the MISO Token Factory
              // Made for Sushi.com 
              // 
              // Enjoy. (c) Chef Gonpachi 2021 
              // <https://github.com/chefgonpachi/MISO/>
              //
              // ---------------------------------------------------------------------
              // SPDX-License-Identifier: GPL-3.0                        
              // ---------------------------------------------------------------------
              
              contract SushiToken is IMisoToken, AccessControl, ERC20 {
              
                  /// @notice Miso template id for the token factory.
                  /// @dev For different token types, this must be incremented.
                  uint256 public constant override tokenTemplate = 3;
              
                  bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
              
                  function initToken(string memory _name, string memory _symbol, address _owner, uint256 _initialSupply) public {
                      _initERC20(_name, _symbol);
                      _setupRole(DEFAULT_ADMIN_ROLE, _owner);
                      _setupRole(MINTER_ROLE, _owner);
                      _mint(msg.sender, _initialSupply);
              
                  }
              
                  function init(bytes calldata _data) external override payable {}
              
                  function initToken(
                      bytes calldata _data
                  ) public override {
                      (string memory _name,
                      string memory _symbol,
                      address _owner,
                      uint256 _initialSupply) = abi.decode(_data, (string, string, address, uint256));
              
                      initToken(_name,_symbol,_owner,_initialSupply);
                  }
              
                 /** 
                   * @dev Generates init data for Token Factory
                   * @param _name - Token name
                   * @param _symbol - Token symbol
                   * @param _owner - Contract owner
                   * @param _initialSupply Amount of tokens minted on creation
                */
                  function getInitData(
                      string calldata _name,
                      string calldata _symbol,
                      address _owner,
                      uint256 _initialSupply
                  )
                      external
                      pure
                      returns (bytes memory _data)
                  {
                      return abi.encode(_name, _symbol, _owner, _initialSupply);
                  }
              
              
                  /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).
                  function mint(address _to, uint256 _amount) public  {
                      require(hasRole(MINTER_ROLE, _msgSender()), "SushiToken: must have minter role to mint");
                      _mint(_to, _amount);
                      _moveDelegates(address(0), _delegates[_to], _amount);
                  }
              
                  // Copied and modified from YAM code:
                  // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol
                  // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol
                  // Which is copied and modified from COMPOUND:
                  // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol
              
                  /// @notice A record of each accounts delegate
                  mapping (address => address) internal _delegates;
              
                  /// @notice A checkpoint for marking number of votes from a given block
                  struct Checkpoint {
                      uint32 fromBlock;
                      uint256 votes;
                  }
              
                  /// @notice A record of votes checkpoints for each account, by index
                  mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
              
                  /// @notice The number of checkpoints for each account
                  mapping (address => uint32) public numCheckpoints;
              
                  /// @notice The EIP-712 typehash for the contract's domain
                  bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
              
                  /// @notice The EIP-712 typehash for the delegation struct used by the contract
                  bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
              
                  /// @notice A record of states for signing / validating signatures
                  mapping (address => uint) public sigNonces;
              
                    /// @notice An event thats emitted when an account changes its delegate
                  event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
              
                  /// @notice An event thats emitted when a delegate account's vote balance changes
                  event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
              
                  /**
                   * @notice Delegate votes from `msg.sender` to `delegatee`
                   * @param delegator The address to get delegatee for
                   */
                  function delegates(address delegator)
                      external
                      view
                      returns (address)
                  {
                      return _delegates[delegator];
                  }
              
                 /**
                  * @notice Delegate votes from `msg.sender` to `delegatee`
                  * @param delegatee The address to delegate votes to
                  */
                  function delegate(address delegatee) external {
                      return _delegate(msg.sender, delegatee);
                  }
              
                  /**
                   * @notice Delegates votes from signatory to `delegatee`
                   * @param delegatee The address to delegate votes to
                   * @param nonce The contract state required to match the signature
                   * @param expiry The time at which to expire the signature
                   * @param v The recovery byte of the signature
                   * @param r Half of the ECDSA signature pair
                   * @param s Half of the ECDSA signature pair
                   */
                  function delegateBySig(
                      address delegatee,
                      uint nonce,
                      uint expiry,
                      uint8 v,
                      bytes32 r,
                      bytes32 s
                  )
                      external
                  {
                      bytes32 domainSeparator = keccak256(
                          abi.encode(
                              DOMAIN_TYPEHASH,
                              keccak256(bytes(name())),
                              getChainId(),
                              address(this)
                          )
                      );
              
                      bytes32 structHash = keccak256(
                          abi.encode(
                              DELEGATION_TYPEHASH,
                              delegatee,
                              nonce,
                              expiry
                          )
                      );
              
                      bytes32 digest = keccak256(
                          abi.encodePacked(
                              "\x19\x01",
                              domainSeparator,
                              structHash
                          )
                      );
              
                      address signatory = ecrecover(digest, v, r, s);
                      require(signatory != address(0), "SUSHI::delegateBySig: invalid signature");
                      require(nonce == sigNonces[signatory]++, "SUSHI::delegateBySig: invalid nonce");
                      require(now <= expiry, "SUSHI::delegateBySig: signature expired");
                      return _delegate(signatory, delegatee);
                  }
              
                  /**
                   * @notice Gets the current votes balance for `account`
                   * @param account The address to get votes balance
                   * @return The number of current votes for `account`
                   */
                  function getCurrentVotes(address account)
                      external
                      view
                      returns (uint256)
                  {
                      uint32 nCheckpoints = numCheckpoints[account];
                      return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
                  }
              
                  /**
                   * @notice Determine the prior number of votes for an account as of a block number
                   * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
                   * @param account The address of the account to check
                   * @param blockNumber The block number to get the vote balance at
                   * @return The number of votes the account had as of the given block
                   */
                  function getPriorVotes(address account, uint blockNumber)
                      external
                      view
                      returns (uint256)
                  {
                      require(blockNumber < block.number, "SUSHI::getPriorVotes: not yet determined");
              
                      uint32 nCheckpoints = numCheckpoints[account];
                      if (nCheckpoints == 0) {
                          return 0;
                      }
              
                      // First check most recent balance
                      if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                          return checkpoints[account][nCheckpoints - 1].votes;
                      }
              
                      // Next check implicit zero balance
                      if (checkpoints[account][0].fromBlock > blockNumber) {
                          return 0;
                      }
              
                      uint32 lower = 0;
                      uint32 upper = nCheckpoints - 1;
                      while (upper > lower) {
                          uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                          Checkpoint memory cp = checkpoints[account][center];
                          if (cp.fromBlock == blockNumber) {
                              return cp.votes;
                          } else if (cp.fromBlock < blockNumber) {
                              lower = center;
                          } else {
                              upper = center - 1;
                          }
                      }
                      return checkpoints[account][lower].votes;
                  }
              
                  function _delegate(address delegator, address delegatee)
                      internal
                  {
                      address currentDelegate = _delegates[delegator];
                      uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SUSHIs (not scaled);
                      _delegates[delegator] = delegatee;
              
                      emit DelegateChanged(delegator, currentDelegate, delegatee);
              
                      _moveDelegates(currentDelegate, delegatee, delegatorBalance);
                  }
              
                  function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {
                      if (srcRep != dstRep && amount > 0) {
                          if (srcRep != address(0)) {
                              // decrease old representative
                              uint32 srcRepNum = numCheckpoints[srcRep];
                              uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                              uint256 srcRepNew = srcRepOld.sub(amount);
                              _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                          }
              
                          if (dstRep != address(0)) {
                              // increase new representative
                              uint32 dstRepNum = numCheckpoints[dstRep];
                              uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                              uint256 dstRepNew = dstRepOld.add(amount);
                              _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                          }
                      }
                  }
              
                  function _writeCheckpoint(
                      address delegatee,
                      uint32 nCheckpoints,
                      uint256 oldVotes,
                      uint256 newVotes
                  )
                      internal
                  {
                      uint32 blockNumber = safe32(block.number, "SUSHI::_writeCheckpoint: block number exceeds 32 bits");
              
                      if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
                          checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
                      } else {
                          checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                          numCheckpoints[delegatee] = nCheckpoints + 1;
                      }
              
                      emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
                  }
              
                  function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
                      require(n < 2**32, errorMessage);
                      return uint32(n);
                  }
              
                  function getChainId() internal pure returns (uint) {
                      uint256 chainId;
                      assembly { chainId := chainid() }
                      return chainId;
                  }
              }