ETH Price: $4,029.75 (+2.65%)

Transaction Decoder

Block:
23612170 at Oct-19-2025 02:06:59 PM +UTC
Transaction Fee:
0.00034554122015424 ETH $1.39
Gas Used:
206,690 Gas / 1.671784896 Gwei

Emitted Events:

260 Vyper_contract.Transfer( _from=0xf1d547f657a05A4A081F899070A5585eb9F326b2, _to=[Receiver] 0x635893bb6ce1d16ac694e141e5f9f09e04f06919, _value=5366738089949503839231 )
261 ConvexToken.Transfer( from=0x0000000000000000000000000000000000000000, to=[Receiver] 0x635893bb6ce1d16ac694e141e5f9f09e04f06919, value=5366738089949503839 )
262 0xf1d547f657a05a4a081f899070a5585eb9f326b2.0xe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486( 0xe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486, 0x000000000000000000000000635893bb6ce1d16ac694e141e5f9f09e04f06919, 000000000000000000000000000000000000000000000122ee73d29cae8e5bff )
263 Vyper_contract.Transfer( _from=[Receiver] 0x635893bb6ce1d16ac694e141e5f9f09e04f06919, _to=[Sender] 0x3be3a8613dc18554a73773a5bfb8e9819d360dc0, _value=5366738089949503839231 )
264 ConvexToken.Transfer( from=[Receiver] 0x635893bb6ce1d16ac694e141e5f9f09e04f06919, to=[Sender] 0x3be3a8613dc18554a73773a5bfb8e9819d360dc0, value=5366738089949503839 )

Account State Difference:

  Address   Before After State Difference Code
0x3be3A861...19d360Dc0
0.016362112445733679 Eth
Nonce: 3124
0.016016571225579439 Eth
Nonce: 3125
0.00034554122015424
(Titan Builder)
18.190834571608130132 Eth18.191144606608130132 Eth0.000310035
0x4e3FBD56...9da5B9D2B
0xD533a949...bA034cd52
0xf1d547f6...eb9F326b2

Execution Trace

0x635893bb6ce1d16ac694e141e5f9f09e04f06919.CALL( )
  • 0x141e4a7efe8addb63d4a51b30a9a8656ce0678f5.DELEGATECALL( )
    • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.7050ccd9( )
      • Vyper_contract.transfer( _to=0x635893bb6CE1d16ac694E141E5F9f09e04F06919, _value=5366738089949503839231 ) => ( True )
      • Booster.rewardClaimed( _pid=398, _address=0x635893bb6CE1d16ac694E141E5F9f09e04F06919, _amount=5366738089949503839231 ) => ( True )
        • ConvexToken.mint( _to=0x635893bb6CE1d16ac694E141E5F9f09e04F06919, _amount=5366738089949503839231 )
        • 0xf38b8eccfcf3c908115fb7bde4e9402374238f27.c00007b0( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.70a08231( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.70a08231( )
          • Vyper_contract.balanceOf( arg0=0x635893bb6CE1d16ac694E141E5F9f09e04F06919 ) => ( 5366738089949503839231 )
          • Vyper_contract.transfer( _to=0x3be3A8613dC18554a73773a5Bfb8E9819d360Dc0, _value=5366738089949503839231 ) => ( True )
          • ConvexToken.balanceOf( account=0x635893bb6CE1d16ac694E141E5F9f09e04F06919 ) => ( 5366738089949503839 )
          • ConvexToken.transfer( recipient=0x3be3A8613dC18554a73773a5Bfb8E9819d360Dc0, amount=5366738089949503839 ) => ( True )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.STATICCALL( )
          • 0xf1d547f657a05a4a081f899070a5585eb9f326b2.40c35446( )
          • 0xf38b8eccfcf3c908115fb7bde4e9402374238f27.STATICCALL( )
          • 0xe24fe375988407f4acc552870db5b027fe5a358e.CALL( )
            • StashTokenWrapper.DELEGATECALL( )
            • ConvexToken.balanceOf( account=0x635893bb6CE1d16ac694E141E5F9f09e04F06919 ) => ( 0 )
              File 1 of 4: Vyper_contract
              # @version 0.2.4
              """
              @title Curve DAO Token
              @author Curve Finance
              @license MIT
              @notice ERC20 with piecewise-linear mining supply.
              @dev Based on the ERC-20 token standard as defined at
                   https://eips.ethereum.org/EIPS/eip-20
              """
              
              from vyper.interfaces import ERC20
              
              implements: ERC20
              
              
              event Transfer:
                  _from: indexed(address)
                  _to: indexed(address)
                  _value: uint256
              
              event Approval:
                  _owner: indexed(address)
                  _spender: indexed(address)
                  _value: uint256
              
              event UpdateMiningParameters:
                  time: uint256
                  rate: uint256
                  supply: uint256
              
              event SetMinter:
                  minter: address
              
              event SetAdmin:
                  admin: address
              
              
              name: public(String[64])
              symbol: public(String[32])
              decimals: public(uint256)
              
              balanceOf: public(HashMap[address, uint256])
              allowances: HashMap[address, HashMap[address, uint256]]
              total_supply: uint256
              
              minter: public(address)
              admin: public(address)
              
              # General constants
              YEAR: constant(uint256) = 86400 * 365
              
              # Allocation:
              # =========
              # * shareholders - 30%
              # * emplyees - 3%
              # * DAO-controlled reserve - 5%
              # * Early users - 5%
              # == 43% ==
              # left for inflation: 57%
              
              # Supply parameters
              INITIAL_SUPPLY: constant(uint256) = 1_303_030_303
              INITIAL_RATE: constant(uint256) = 274_815_283 * 10 ** 18 / YEAR  # leading to 43% premine
              RATE_REDUCTION_TIME: constant(uint256) = YEAR
              RATE_REDUCTION_COEFFICIENT: constant(uint256) = 1189207115002721024  # 2 ** (1/4) * 1e18
              RATE_DENOMINATOR: constant(uint256) = 10 ** 18
              INFLATION_DELAY: constant(uint256) = 86400
              
              # Supply variables
              mining_epoch: public(int128)
              start_epoch_time: public(uint256)
              rate: public(uint256)
              
              start_epoch_supply: uint256
              
              
              @external
              def __init__(_name: String[64], _symbol: String[32], _decimals: uint256):
                  """
                  @notice Contract constructor
                  @param _name Token full name
                  @param _symbol Token symbol
                  @param _decimals Number of decimals for token
                  """
                  init_supply: uint256 = INITIAL_SUPPLY * 10 ** _decimals
                  self.name = _name
                  self.symbol = _symbol
                  self.decimals = _decimals
                  self.balanceOf[msg.sender] = init_supply
                  self.total_supply = init_supply
                  self.admin = msg.sender
                  log Transfer(ZERO_ADDRESS, msg.sender, init_supply)
              
                  self.start_epoch_time = block.timestamp + INFLATION_DELAY - RATE_REDUCTION_TIME
                  self.mining_epoch = -1
                  self.rate = 0
                  self.start_epoch_supply = init_supply
              
              
              @internal
              def _update_mining_parameters():
                  """
                  @dev Update mining rate and supply at the start of the epoch
                       Any modifying mining call must also call this
                  """
                  _rate: uint256 = self.rate
                  _start_epoch_supply: uint256 = self.start_epoch_supply
              
                  self.start_epoch_time += RATE_REDUCTION_TIME
                  self.mining_epoch += 1
              
                  if _rate == 0:
                      _rate = INITIAL_RATE
                  else:
                      _start_epoch_supply += _rate * RATE_REDUCTION_TIME
                      self.start_epoch_supply = _start_epoch_supply
                      _rate = _rate * RATE_DENOMINATOR / RATE_REDUCTION_COEFFICIENT
              
                  self.rate = _rate
              
                  log UpdateMiningParameters(block.timestamp, _rate, _start_epoch_supply)
              
              
              @external
              def update_mining_parameters():
                  """
                  @notice Update mining rate and supply at the start of the epoch
                  @dev Callable by any address, but only once per epoch
                       Total supply becomes slightly larger if this function is called late
                  """
                  assert block.timestamp >= self.start_epoch_time + RATE_REDUCTION_TIME  # dev: too soon!
                  self._update_mining_parameters()
              
              
              @external
              def start_epoch_time_write() -> uint256:
                  """
                  @notice Get timestamp of the current mining epoch start
                          while simultaneously updating mining parameters
                  @return Timestamp of the epoch
                  """
                  _start_epoch_time: uint256 = self.start_epoch_time
                  if block.timestamp >= _start_epoch_time + RATE_REDUCTION_TIME:
                      self._update_mining_parameters()
                      return self.start_epoch_time
                  else:
                      return _start_epoch_time
              
              
              @external
              def future_epoch_time_write() -> uint256:
                  """
                  @notice Get timestamp of the next mining epoch start
                          while simultaneously updating mining parameters
                  @return Timestamp of the next epoch
                  """
                  _start_epoch_time: uint256 = self.start_epoch_time
                  if block.timestamp >= _start_epoch_time + RATE_REDUCTION_TIME:
                      self._update_mining_parameters()
                      return self.start_epoch_time + RATE_REDUCTION_TIME
                  else:
                      return _start_epoch_time + RATE_REDUCTION_TIME
              
              
              @internal
              @view
              def _available_supply() -> uint256:
                  return self.start_epoch_supply + (block.timestamp - self.start_epoch_time) * self.rate
              
              
              @external
              @view
              def available_supply() -> uint256:
                  """
                  @notice Current number of tokens in existence (claimed or unclaimed)
                  """
                  return self._available_supply()
              
              
              @external
              @view
              def mintable_in_timeframe(start: uint256, end: uint256) -> uint256:
                  """
                  @notice How much supply is mintable from start timestamp till end timestamp
                  @param start Start of the time interval (timestamp)
                  @param end End of the time interval (timestamp)
                  @return Tokens mintable from `start` till `end`
                  """
                  assert start <= end  # dev: start > end
                  to_mint: uint256 = 0
                  current_epoch_time: uint256 = self.start_epoch_time
                  current_rate: uint256 = self.rate
              
                  # Special case if end is in future (not yet minted) epoch
                  if end > current_epoch_time + RATE_REDUCTION_TIME:
                      current_epoch_time += RATE_REDUCTION_TIME
                      current_rate = current_rate * RATE_DENOMINATOR / RATE_REDUCTION_COEFFICIENT
              
                  assert end <= current_epoch_time + RATE_REDUCTION_TIME  # dev: too far in future
              
                  for i in range(999):  # Curve will not work in 1000 years. Darn!
                      if end >= current_epoch_time:
                          current_end: uint256 = end
                          if current_end > current_epoch_time + RATE_REDUCTION_TIME:
                              current_end = current_epoch_time + RATE_REDUCTION_TIME
              
                          current_start: uint256 = start
                          if current_start >= current_epoch_time + RATE_REDUCTION_TIME:
                              break  # We should never get here but what if...
                          elif current_start < current_epoch_time:
                              current_start = current_epoch_time
              
                          to_mint += current_rate * (current_end - current_start)
              
                          if start >= current_epoch_time:
                              break
              
                      current_epoch_time -= RATE_REDUCTION_TIME
                      current_rate = current_rate * RATE_REDUCTION_COEFFICIENT / RATE_DENOMINATOR  # double-division with rounding made rate a bit less => good
                      assert current_rate <= INITIAL_RATE  # This should never happen
              
                  return to_mint
              
              
              @external
              def set_minter(_minter: address):
                  """
                  @notice Set the minter address
                  @dev Only callable once, when minter has not yet been set
                  @param _minter Address of the minter
                  """
                  assert msg.sender == self.admin  # dev: admin only
                  assert self.minter == ZERO_ADDRESS  # dev: can set the minter only once, at creation
                  self.minter = _minter
                  log SetMinter(_minter)
              
              
              @external
              def set_admin(_admin: address):
                  """
                  @notice Set the new admin.
                  @dev After all is set up, admin only can change the token name
                  @param _admin New admin address
                  """
                  assert msg.sender == self.admin  # dev: admin only
                  self.admin = _admin
                  log SetAdmin(_admin)
              
              
              @external
              @view
              def totalSupply() -> uint256:
                  """
                  @notice Total number of tokens in existence.
                  """
                  return self.total_supply
              
              
              @external
              @view
              def allowance(_owner : address, _spender : address) -> uint256:
                  """
                  @notice Check the amount of tokens that an owner allowed to a spender
                  @param _owner The address which owns the funds
                  @param _spender The address which will spend the funds
                  @return uint256 specifying the amount of tokens still available for the spender
                  """
                  return self.allowances[_owner][_spender]
              
              
              @external
              def transfer(_to : address, _value : uint256) -> bool:
                  """
                  @notice Transfer `_value` tokens from `msg.sender` to `_to`
                  @dev Vyper does not allow underflows, so the subtraction in
                       this function will revert on an insufficient balance
                  @param _to The address to transfer to
                  @param _value The amount to be transferred
                  @return bool success
                  """
                  assert _to != ZERO_ADDRESS  # dev: transfers to 0x0 are not allowed
                  self.balanceOf[msg.sender] -= _value
                  self.balanceOf[_to] += _value
                  log Transfer(msg.sender, _to, _value)
                  return True
              
              
              @external
              def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
                  """
                   @notice Transfer `_value` tokens from `_from` to `_to`
                   @param _from address The address which you want to send tokens from
                   @param _to address The address which you want to transfer to
                   @param _value uint256 the amount of tokens to be transferred
                   @return bool success
                  """
                  assert _to != ZERO_ADDRESS  # dev: transfers to 0x0 are not allowed
                  # NOTE: vyper does not allow underflows
                  #       so the following subtraction would revert on insufficient balance
                  self.balanceOf[_from] -= _value
                  self.balanceOf[_to] += _value
                  self.allowances[_from][msg.sender] -= _value
                  log Transfer(_from, _to, _value)
                  return True
              
              
              @external
              def approve(_spender : address, _value : uint256) -> bool:
                  """
                  @notice Approve `_spender` to transfer `_value` tokens on behalf of `msg.sender`
                  @dev Approval may only be from zero -> nonzero or from nonzero -> zero in order
                      to mitigate the potential race condition described here:
                      https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                  @param _spender The address which will spend the funds
                  @param _value The amount of tokens to be spent
                  @return bool success
                  """
                  assert _value == 0 or self.allowances[msg.sender][_spender] == 0
                  self.allowances[msg.sender][_spender] = _value
                  log Approval(msg.sender, _spender, _value)
                  return True
              
              
              @external
              def mint(_to: address, _value: uint256) -> bool:
                  """
                  @notice Mint `_value` tokens and assign them to `_to`
                  @dev Emits a Transfer event originating from 0x00
                  @param _to The account that will receive the created tokens
                  @param _value The amount that will be created
                  @return bool success
                  """
                  assert msg.sender == self.minter  # dev: minter only
                  assert _to != ZERO_ADDRESS  # dev: zero address
              
                  if block.timestamp >= self.start_epoch_time + RATE_REDUCTION_TIME:
                      self._update_mining_parameters()
              
                  _total_supply: uint256 = self.total_supply + _value
                  assert _total_supply <= self._available_supply()  # dev: exceeds allowable mint amount
                  self.total_supply = _total_supply
              
                  self.balanceOf[_to] += _value
                  log Transfer(ZERO_ADDRESS, _to, _value)
              
                  return True
              
              
              @external
              def burn(_value: uint256) -> bool:
                  """
                  @notice Burn `_value` tokens belonging to `msg.sender`
                  @dev Emits a Transfer event with a destination of 0x00
                  @param _value The amount that will be burned
                  @return bool success
                  """
                  self.balanceOf[msg.sender] -= _value
                  self.total_supply -= _value
              
                  log Transfer(msg.sender, ZERO_ADDRESS, _value)
                  return True
              
              
              @external
              def set_name(_name: String[64], _symbol: String[32]):
                  """
                  @notice Change the token name and symbol to `_name` and `_symbol`
                  @dev Only callable by the admin account
                  @param _name New token name
                  @param _symbol New token symbol
                  """
                  assert msg.sender == self.admin, "Only admin is allowed to change name"
                  self.name = _name
                  self.symbol = _symbol

              File 2 of 4: ConvexToken
              // SPDX-License-Identifier: MIT
              
              
              // File: contracts\Interfaces.sol
              pragma solidity 0.6.12;
              
              /**
               * @dev Standard math utilities missing in the Solidity language.
               */
              library MathUtil {
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a < b ? a : b;
                  }
              }
              
              contract ReentrancyGuard {
                  uint256 private _guardCounter;
              
                  constructor () internal {
                      _guardCounter = 1;
                  }
              
                  modifier nonReentrant() {
                      _guardCounter += 1;
                      uint256 localCounter = _guardCounter;
                      _;
                      require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
                  }
              }
              
              interface ICurveGauge {
                  function deposit(uint256) external;
                  function balanceOf(address) external view returns (uint256);
                  function withdraw(uint256) external;
                  function claim_rewards() external;
                  function reward_tokens(uint256) external view returns(address);//v2
                  function rewarded_token() external view returns(address);//v1
              }
              
              interface ICurveVoteEscrow {
                  function create_lock(uint256, uint256) external;
                  function increase_amount(uint256) external;
                  function increase_unlock_time(uint256) external;
                  function withdraw() external;
                  function smart_wallet_checker() external view returns (address);
              }
              
              interface IWalletChecker {
                  function check(address) external view returns (bool);
              }
              
              interface IVoting{
                  function vote(uint256, bool, bool) external; //voteId, support, executeIfDecided
                  function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); 
                  function vote_for_gauge_weights(address,uint256) external;
              }
              
              interface IMinter{
                  function mint(address) external;
              }
              
              interface IRegistry{
                  function get_registry() external view returns(address);
                  function get_address(uint256 _id) external view returns(address);
                  function gauge_controller() external view returns(address);
                  function get_lp_token(address) external view returns(address);
                  function get_gauges(address) external view returns(address[10] memory,uint128[10] memory);
              }
              
              interface IStaker{
                  function deposit(address, address) external;
                  function withdraw(address) external;
                  function withdraw(address, address, uint256) external;
                  function withdrawAll(address, address) external;
                  function createLock(uint256, uint256) external;
                  function increaseAmount(uint256) external;
                  function increaseTime(uint256) external;
                  function release() external;
                  function claimCrv(address) external returns (uint256);
                  function claimRewards(address) external;
                  function claimFees(address,address) external;
                  function setStashAccess(address, bool) external;
                  function vote(uint256,address,bool) external;
                  function voteGaugeWeight(address,uint256) external;
                  function balanceOfPool(address) external view returns (uint256);
                  function operator() external view returns (address);
                  function execute(address _to, uint256 _value, bytes calldata _data) external returns (bool, bytes memory);
              }
              
              interface IRewards{
                  function stake(address, uint256) external;
                  function stakeFor(address, uint256) external;
                  function withdraw(address, uint256) external;
                  function exit(address) external;
                  function getReward(address) external;
                  function queueNewRewards(uint256) external;
                  function notifyRewardAmount(uint256) external;
                  function addExtraReward(address) external;
                  function stakingToken() external returns (address);
              }
              
              interface IStash{
                  function stashRewards() external returns (bool);
                  function processStash() external returns (bool);
                  function claimRewards() external returns (bool);
              }
              
              interface IFeeDistro{
                  function claim() external;
                  function token() external view returns(address);
              }
              
              interface ITokenMinter{
                  function mint(address,uint256) external;
                  function burn(address,uint256) external;
              }
              
              interface IDeposit{
                  function isShutdown() external view returns(bool);
                  function balanceOf(address _account) external view returns(uint256);
                  function totalSupply() external view returns(uint256);
                  function poolInfo(uint256) external view returns(address,address,address,address,address, bool);
                  function rewardClaimed(uint256,address,uint256) external;
                  function withdrawTo(uint256,uint256,address) external;
                  function claimRewards(uint256,address) external returns(bool);
                  function rewardArbitrator() external returns(address);
              }
              
              interface ICrvDeposit{
                  function deposit(uint256, bool) external;
                  function lockIncentive() external view returns(uint256);
              }
              
              interface IRewardFactory{
                  function setAccess(address,bool) external;
                  function CreateCrvRewards(uint256,address) external returns(address);
                  function CreateTokenRewards(address,address,address) external returns(address);
                  function activeRewardCount(address) external view returns(uint256);
                  function addActiveReward(address,uint256) external returns(bool);
                  function removeActiveReward(address,uint256) external returns(bool);
              }
              
              interface IStashFactory{
                  function CreateStash(uint256,address,address,uint256) external returns(address);
              }
              
              interface ITokenFactory{
                  function CreateDepositToken(address) external returns(address);
              }
              
              interface IPools{
                  function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool);
                  function shutdownPool(uint256 _pid) external returns(bool);
                  function poolInfo(uint256) external view returns(address,address,address,address,address,bool);
                  function poolLength() external view returns (uint256);
                  function gaugeMap(address) external view returns(bool);
                  function setPoolManager(address _poolM) external;
              }
              
              interface IVestedEscrow{
                  function fund(address[] calldata _recipient, uint256[] calldata _amount) external returns(bool);
              }
              
              // File: @openzeppelin\contracts\math\SafeMath.sol
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /**
               * @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: @openzeppelin\contracts\token\ERC20\IERC20.sol
              
              
              pragma solidity >=0.6.0 <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\contracts\utils\Address.sol
              
              pragma solidity >=0.6.2 <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\contracts\token\ERC20\SafeERC20.sol
              
              pragma solidity >=0.6.0 <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 SafeMath for uint256;
                  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).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _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: node_modules\@openzeppelin\contracts\utils\Context.sol
              
              pragma solidity >=0.6.0 <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 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: @openzeppelin\contracts\token\ERC20\ERC20.sol
              
              pragma solidity >=0.6.0 <0.8.0;
              
              
              /**
               * @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 Context, IERC20 {
                  using SafeMath for uint256;
              
                  mapping (address => uint256) private _balances;
              
                  mapping (address => mapping (address => uint256)) private _allowances;
              
                  uint256 private _totalSupply;
              
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
              
                  /**
                   * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                   * a default value of 18.
                   *
                   * To select a different value for {decimals}, use {_setupDecimals}.
                   *
                   * All three of these values are immutable: they can only be set once during
                   * construction.
                   */
                  constructor (string memory name_, string memory symbol_) public {
                      _name = name_;
                      _symbol = symbol_;
                      _decimals = 18;
                  }
              
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view virtual returns (string memory) {
                      return _name;
                  }
              
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view virtual 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 virtual returns (uint8) {
                      return _decimals;
                  }
              
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view virtual override returns (uint256) {
                      return _totalSupply;
                  }
              
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view virtual override returns (uint256) {
                      return _balances[account];
                  }
              
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `recipient` cannot be the zero address.
                   * - the caller must have a balance of at least `amount`.
                   */
                  function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                      _transfer(_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;
                  }
              
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Emits an {Approval} event indicating the updated allowance. This is not
                   * required by the EIP. See the note at the beginning of {ERC20}.
                   *
                   * Requirements:
                   *
                   * - `sender` and `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   * - the caller must have allowance for ``sender``'s tokens of at least
                   * `amount`.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                      _transfer(sender, recipient, amount);
                      _approve(sender, _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 virtual {
                      _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\Cvx.sol
              
              pragma solidity 0.6.12;
              
              
              contract ConvexToken is ERC20{
                  using SafeERC20 for IERC20;
                  using Address for address;
                  using SafeMath for uint256;
              
                  address public operator;
                  address public vecrvProxy;
              
                  uint256 public maxSupply = 100 * 1000000 * 1e18; //100mil
                  uint256 public totalCliffs = 1000;
                  uint256 public reductionPerCliff;
              
                  constructor(address _proxy)
                      public
                      ERC20(
                          "Convex Token",
                          "CVX"
                      )
                  {
                      operator = msg.sender;
                      vecrvProxy = _proxy;
                      reductionPerCliff = maxSupply.div(totalCliffs);
                  }
              
                  //get current operator off proxy incase there was a change
                  function updateOperator() public {
                      operator = IStaker(vecrvProxy).operator();
                  }
                  
                  function mint(address _to, uint256 _amount) external {
                      if(msg.sender != operator){
                          //dont error just return. if a shutdown happens, rewards on old system
                          //can still be claimed, just wont mint cvx
                          return;
                      }
              
                      uint256 supply = totalSupply();
                      if(supply == 0){
                          //premine, one time only
                          _mint(_to,_amount);
                          //automatically switch operators
                          updateOperator();
                          return;
                      }
                      
                      //use current supply to gauge cliff
                      //this will cause a bit of overflow into the next cliff range
                      //but should be within reasonable levels.
                      //requires a max supply check though
                      uint256 cliff = supply.div(reductionPerCliff);
                      //mint if below total cliffs
                      if(cliff < totalCliffs){
                          //for reduction% take inverse of current cliff
                          uint256 reduction = totalCliffs.sub(cliff);
                          //reduce
                          _amount = _amount.mul(reduction).div(totalCliffs);
              
                          //supply cap check
                          uint256 amtTillMax = maxSupply.sub(supply);
                          if(_amount > amtTillMax){
                              _amount = amtTillMax;
                          }
              
                          //mint
                          _mint(_to, _amount);
                      }
                  }
              
              }

              File 3 of 4: Booster
              // SPDX-License-Identifier: MIT
              // File: contracts\Interfaces.sol
              
              pragma solidity 0.6.12;
              
              /**
               * @dev Standard math utilities missing in the Solidity language.
               */
              library MathUtil {
                  /**
                   * @dev Returns the smallest of two numbers.
                   */
                  function min(uint256 a, uint256 b) internal pure returns (uint256) {
                      return a < b ? a : b;
                  }
              }
              
              contract ReentrancyGuard {
                  uint256 private _guardCounter;
              
                  constructor () internal {
                      _guardCounter = 1;
                  }
              
                  modifier nonReentrant() {
                      _guardCounter += 1;
                      uint256 localCounter = _guardCounter;
                      _;
                      require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
                  }
              }
              
              interface ICurveGauge {
                  function deposit(uint256) external;
                  function balanceOf(address) external view returns (uint256);
                  function withdraw(uint256) external;
                  function claim_rewards() external;
                  function reward_tokens(uint256) external view returns(address);//v2
                  function rewarded_token() external view returns(address);//v1
              }
              
              interface ICurveVoteEscrow {
                  function create_lock(uint256, uint256) external;
                  function increase_amount(uint256) external;
                  function increase_unlock_time(uint256) external;
                  function withdraw() external;
                  function smart_wallet_checker() external view returns (address);
              }
              
              interface IWalletChecker {
                  function check(address) external view returns (bool);
              }
              
              interface IVoting{
                  function vote(uint256, bool, bool) external; //voteId, support, executeIfDecided
                  function getVote(uint256) external view returns(bool,bool,uint64,uint64,uint64,uint64,uint256,uint256,uint256,bytes memory); 
                  function vote_for_gauge_weights(address,uint256) external;
              }
              
              interface IMinter{
                  function mint(address) external;
              }
              
              interface IRegistry{
                  function get_registry() external view returns(address);
                  function get_address(uint256 _id) external view returns(address);
                  function gauge_controller() external view returns(address);
                  function get_lp_token(address) external view returns(address);
                  function get_gauges(address) external view returns(address[10] memory,uint128[10] memory);
              }
              
              interface IStaker{
                  function deposit(address, address) external;
                  function withdraw(address) external;
                  function withdraw(address, address, uint256) external;
                  function withdrawAll(address, address) external;
                  function createLock(uint256, uint256) external;
                  function increaseAmount(uint256) external;
                  function increaseTime(uint256) external;
                  function release() external;
                  function claimCrv(address) external returns (uint256);
                  function claimRewards(address) external;
                  function claimFees(address,address) external;
                  function setStashAccess(address, bool) external;
                  function vote(uint256,address,bool) external;
                  function voteGaugeWeight(address,uint256) external;
                  function balanceOfPool(address) external view returns (uint256);
                  function operator() external view returns (address);
                  function execute(address _to, uint256 _value, bytes calldata _data) external returns (bool, bytes memory);
              }
              
              interface IRewards{
                  function stake(address, uint256) external;
                  function stakeFor(address, uint256) external;
                  function withdraw(address, uint256) external;
                  function exit(address) external;
                  function getReward(address) external;
                  function queueNewRewards(uint256) external;
                  function notifyRewardAmount(uint256) external;
                  function addExtraReward(address) external;
                  function stakingToken() external returns (address);
              }
              
              interface IStash{
                  function stashRewards() external returns (bool);
                  function processStash() external returns (bool);
                  function claimRewards() external returns (bool);
              }
              
              interface IFeeDistro{
                  function claim() external;
                  function token() external view returns(address);
              }
              
              interface ITokenMinter{
                  function mint(address,uint256) external;
                  function burn(address,uint256) external;
              }
              
              interface IDeposit{
                  function isShutdown() external view returns(bool);
                  function balanceOf(address _account) external view returns(uint256);
                  function totalSupply() external view returns(uint256);
                  function poolInfo(uint256) external view returns(address,address,address,address,address, bool);
                  function rewardClaimed(uint256,address,uint256) external;
                  function withdrawTo(uint256,uint256,address) external;
                  function claimRewards(uint256,address) external returns(bool);
                  function rewardArbitrator() external returns(address);
              }
              
              interface ICrvDeposit{
                  function deposit(uint256, bool) external;
                  function lockIncentive() external view returns(uint256);
              }
              
              interface IRewardFactory{
                  function setAccess(address,bool) external;
                  function CreateCrvRewards(uint256,address) external returns(address);
                  function CreateTokenRewards(address,address,address) external returns(address);
                  function activeRewardCount(address) external view returns(uint256);
                  function addActiveReward(address,uint256) external returns(bool);
                  function removeActiveReward(address,uint256) external returns(bool);
              }
              
              interface IStashFactory{
                  function CreateStash(uint256,address,address,uint256) external returns(address);
              }
              
              interface ITokenFactory{
                  function CreateDepositToken(address) external returns(address);
              }
              
              interface IPools{
                  function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool);
                  function shutdownPool(uint256 _pid) external returns(bool);
                  function poolInfo(uint256) external view returns(address,address,address,address,address,bool);
                  function poolLength() external view returns (uint256);
                  function gaugeMap(address) external view returns(bool);
                  function setPoolManager(address _poolM) external;
              }
              
              interface IVestedEscrow{
                  function fund(address[] calldata _recipient, uint256[] calldata _amount) external returns(bool);
              }
              
              // File: @openzeppelin\contracts\math\SafeMath.sol
              
              pragma solidity >=0.6.0 <0.8.0;
              
              /**
               * @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: @openzeppelin\contracts\token\ERC20\IERC20.sol
              
              pragma solidity >=0.6.0 <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\contracts\utils\Address.sol
              pragma solidity >=0.6.2 <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\contracts\token\ERC20\SafeERC20.sol
              
              
              pragma solidity >=0.6.0 <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 SafeMath for uint256;
                  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).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _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: contracts\Booster.sol
              
              pragma solidity 0.6.12;
              
              
              
              contract Booster{
                  using SafeERC20 for IERC20;
                  using Address for address;
                  using SafeMath for uint256;
              
                  address public constant crv = address(0xD533a949740bb3306d119CC777fa900bA034cd52);
                  address public constant registry = address(0x0000000022D53366457F9d5E68Ec105046FC4383);
                  uint256 public constant distributionAddressId = 4;
                  address public constant voteOwnership = address(0xE478de485ad2fe566d49342Cbd03E49ed7DB3356);
                  address public constant voteParameter = address(0xBCfF8B0b9419b9A88c44546519b1e909cF330399);
              
                  uint256 public lockIncentive = 1000; //incentive to crv stakers
                  uint256 public stakerIncentive = 450; //incentive to native token stakers
                  uint256 public earmarkIncentive = 50; //incentive to users who spend gas to make calls
                  uint256 public platformFee = 0; //possible fee to build treasury
                  uint256 public constant MaxFees = 2000;
                  uint256 public constant FEE_DENOMINATOR = 10000;
              
                  address public owner;
                  address public feeManager;
                  address public poolManager;
                  address public immutable staker;
                  address public immutable minter;
                  address public rewardFactory;
                  address public stashFactory;
                  address public tokenFactory;
                  address public rewardArbitrator;
                  address public voteDelegate;
                  address public treasury;
                  address public stakerRewards; //cvx rewards
                  address public lockRewards; //cvxCrv rewards(crv)
                  address public lockFees; //cvxCrv vecrv fees
                  address public feeDistro;
                  address public feeToken;
              
                  bool public isShutdown;
              
                  struct PoolInfo {
                      address lptoken;
                      address token;
                      address gauge;
                      address crvRewards;
                      address stash;
                      bool shutdown;
                  }
              
                  //index(pid) -> pool
                  PoolInfo[] public poolInfo;
                  mapping(address => bool) public gaugeMap;
              
                  event Deposited(address indexed user, uint256 indexed poolid, uint256 amount);
                  event Withdrawn(address indexed user, uint256 indexed poolid, uint256 amount);
              
                  constructor(address _staker, address _minter) public {
                      isShutdown = false;
                      staker = _staker;
                      owner = msg.sender;
                      voteDelegate = msg.sender;
                      feeManager = msg.sender;
                      poolManager = msg.sender;
                      feeDistro = address(0); //address(0xA464e6DCda8AC41e03616F95f4BC98a13b8922Dc);
                      feeToken = address(0); //address(0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490);
                      treasury = address(0);
                      minter = _minter;
                  }
              
              
                  /// SETTER SECTION ///
              
                  function setOwner(address _owner) external {
                      require(msg.sender == owner, "!auth");
                      owner = _owner;
                  }
              
                  function setFeeManager(address _feeM) external {
                      require(msg.sender == feeManager, "!auth");
                      feeManager = _feeM;
                  }
              
                  function setPoolManager(address _poolM) external {
                      require(msg.sender == poolManager, "!auth");
                      poolManager = _poolM;
                  }
              
                  function setFactories(address _rfactory, address _sfactory, address _tfactory) external {
                      require(msg.sender == owner, "!auth");
                      
                      //reward factory only allow this to be called once even if owner
                      //removes ability to inject malicious staking contracts
                      //token factory can also be immutable
                      if(rewardFactory == address(0)){
                          rewardFactory = _rfactory;
                          tokenFactory = _tfactory;
                      }
              
                      //stash factory should be considered more safe to change
                      //updating may be required to handle new types of gauges
                      stashFactory = _sfactory;
                  }
              
                  function setArbitrator(address _arb) external {
                      require(msg.sender==owner, "!auth");
                      rewardArbitrator = _arb;
                  }
              
                  function setVoteDelegate(address _voteDelegate) external {
                      require(msg.sender==voteDelegate, "!auth");
                      voteDelegate = _voteDelegate;
                  }
              
                  function setRewardContracts(address _rewards, address _stakerRewards) external {
                      require(msg.sender == owner, "!auth");
                      
                      //reward contracts are immutable or else the owner
                      //has a means to redeploy and mint cvx via rewardClaimed()
                      if(lockRewards == address(0)){
                          lockRewards = _rewards;
                          stakerRewards = _stakerRewards;
                      }
                  }
              
                  // Set reward token and claim contract, get from Curve's registry
                  function setFeeInfo() external {
                      require(msg.sender==feeManager, "!auth");
                      
                      feeDistro = IRegistry(registry).get_address(distributionAddressId);
                      address _feeToken = IFeeDistro(feeDistro).token();
                      if(feeToken != _feeToken){
                          //create a new reward contract for the new token
                          lockFees = IRewardFactory(rewardFactory).CreateTokenRewards(_feeToken,lockRewards,address(this));
                          feeToken = _feeToken;
                      }
                  }
              
                  function setFees(uint256 _lockFees, uint256 _stakerFees, uint256 _callerFees, uint256 _platform) external{
                      require(msg.sender==feeManager, "!auth");
              
                      uint256 total = _lockFees.add(_stakerFees).add(_callerFees).add(_platform);
                      require(total <= MaxFees, ">MaxFees");
              
                      //values must be within certain ranges     
                      if(_lockFees >= 1000 && _lockFees <= 1500
                          && _stakerFees >= 300 && _stakerFees <= 600
                          && _callerFees >= 10 && _callerFees <= 100
                          && _platform <= 200){
                          lockIncentive = _lockFees;
                          stakerIncentive = _stakerFees;
                          earmarkIncentive = _callerFees;
                          platformFee = _platform;
                      }
                  }
              
                  function setTreasury(address _treasury) external {
                      require(msg.sender==feeManager, "!auth");
                      treasury = _treasury;
                  }
              
                  /// END SETTER SECTION ///
              
              
                  function poolLength() external view returns (uint256) {
                      return poolInfo.length;
                  }
              
                  //create a new pool
                  function addPool(address _lptoken, address _gauge, uint256 _stashVersion) external returns(bool){
                      require(msg.sender==poolManager && !isShutdown, "!add");
                      require(_gauge != address(0) && _lptoken != address(0),"!param");
              
                      //the next pool's pid
                      uint256 pid = poolInfo.length;
              
                      //create a tokenized deposit
                      address token = ITokenFactory(tokenFactory).CreateDepositToken(_lptoken);
                      //create a reward contract for crv rewards
                      address newRewardPool = IRewardFactory(rewardFactory).CreateCrvRewards(pid,token);
                      //create a stash to handle extra incentives
                      address stash = IStashFactory(stashFactory).CreateStash(pid,_gauge,staker,_stashVersion);
              
                      //add the new pool
                      poolInfo.push(
                          PoolInfo({
                              lptoken: _lptoken,
                              token: token,
                              gauge: _gauge,
                              crvRewards: newRewardPool,
                              stash: stash,
                              shutdown: false
                          })
                      );
                      gaugeMap[_gauge] = true;
                      //give stashes access to rewardfactory and voteproxy
                      //   voteproxy so it can grab the incentive tokens off the contract after claiming rewards
                      //   reward factory so that stashes can make new extra reward contracts if a new incentive is added to the gauge
                      if(stash != address(0)){
                          poolInfo[pid].stash = stash;
                          IStaker(staker).setStashAccess(stash,true);
                          IRewardFactory(rewardFactory).setAccess(stash,true);
                      }
                      return true;
                  }
              
                  //shutdown pool
                  function shutdownPool(uint256 _pid) external returns(bool){
                      require(msg.sender==poolManager, "!auth");
                      PoolInfo storage pool = poolInfo[_pid];
              
                      //withdraw from gauge
                      try IStaker(staker).withdrawAll(pool.lptoken,pool.gauge){
                      }catch{}
              
                      pool.shutdown = true;
                      gaugeMap[pool.gauge] = false;
                      return true;
                  }
              
                  //shutdown this contract.
                  //  unstake and pull all lp tokens to this address
                  //  only allow withdrawals
                  function shutdownSystem() external{
                      require(msg.sender == owner, "!auth");
                      isShutdown = true;
              
                      for(uint i=0; i < poolInfo.length; i++){
                          PoolInfo storage pool = poolInfo[i];
                          if (pool.shutdown) continue;
              
                          address token = pool.lptoken;
                          address gauge = pool.gauge;
              
                          //withdraw from gauge
                          try IStaker(staker).withdrawAll(token,gauge){
                              pool.shutdown = true;
                          }catch{}
                      }
                  }
              
              
                  //deposit lp tokens and stake
                  function deposit(uint256 _pid, uint256 _amount, bool _stake) public returns(bool){
                      require(!isShutdown,"shutdown");
                      PoolInfo storage pool = poolInfo[_pid];
                      require(pool.shutdown == false, "pool is closed");
              
                      //send to proxy to stake
                      address lptoken = pool.lptoken;
                      IERC20(lptoken).safeTransferFrom(msg.sender, staker, _amount);
              
                      //stake
                      address gauge = pool.gauge;
                      require(gauge != address(0),"!gauge setting");
                      IStaker(staker).deposit(lptoken,gauge);
              
                      //some gauges claim rewards when depositing, stash them in a seperate contract until next claim
                      address stash = pool.stash;
                      if(stash != address(0)){
                          IStash(stash).stashRewards();
                      }
              
                      address token = pool.token;
                      if(_stake){
                          //mint here and send to rewards on user behalf
                          ITokenMinter(token).mint(address(this),_amount);
                          address rewardContract = pool.crvRewards;
                          IERC20(token).safeApprove(rewardContract,0);
                          IERC20(token).safeApprove(rewardContract,_amount);
                          IRewards(rewardContract).stakeFor(msg.sender,_amount);
                      }else{
                          //add user balance directly
                          ITokenMinter(token).mint(msg.sender,_amount);
                      }
              
                      
                      emit Deposited(msg.sender, _pid, _amount);
                      return true;
                  }
              
                  //deposit all lp tokens and stake
                  function depositAll(uint256 _pid, bool _stake) external returns(bool){
                      address lptoken = poolInfo[_pid].lptoken;
                      uint256 balance = IERC20(lptoken).balanceOf(msg.sender);
                      deposit(_pid,balance,_stake);
                      return true;
                  }
              
                  //withdraw lp tokens
                  function _withdraw(uint256 _pid, uint256 _amount, address _from, address _to) internal {
                      PoolInfo storage pool = poolInfo[_pid];
                      address lptoken = pool.lptoken;
                      address gauge = pool.gauge;
              
                      //remove lp balance
                      address token = pool.token;
                      ITokenMinter(token).burn(_from,_amount);
              
                      //pull from gauge if not shutdown
                      // if shutdown tokens will be in this contract
                      if (!pool.shutdown) {
                          IStaker(staker).withdraw(lptoken,gauge, _amount);
                      }
              
                      //some gauges claim rewards when withdrawing, stash them in a seperate contract until next claim
                      //do not call if shutdown since stashes wont have access
                      address stash = pool.stash;
                      if(stash != address(0) && !isShutdown && !pool.shutdown){
                          IStash(stash).stashRewards();
                      }
                      
                      //return lp tokens
                      IERC20(lptoken).safeTransfer(_to, _amount);
              
                      emit Withdrawn(_to, _pid, _amount);
                  }
              
                  //withdraw lp tokens
                  function withdraw(uint256 _pid, uint256 _amount) public returns(bool){
                      _withdraw(_pid,_amount,msg.sender,msg.sender);
                      return true;
                  }
              
                  //withdraw all lp tokens
                  function withdrawAll(uint256 _pid) public returns(bool){
                      address token = poolInfo[_pid].token;
                      uint256 userBal = IERC20(token).balanceOf(msg.sender);
                      withdraw(_pid, userBal);
                      return true;
                  }
              
                  //allow reward contracts to send here and withdraw to user
                  function withdrawTo(uint256 _pid, uint256 _amount, address _to) external returns(bool){
                      address rewardContract = poolInfo[_pid].crvRewards;
                      require(msg.sender == rewardContract,"!auth");
              
                      _withdraw(_pid,_amount,msg.sender,_to);
                      return true;
                  }
              
              
                  //delegate address votes on dao
                  function vote(uint256 _voteId, address _votingAddress, bool _support) external returns(bool){
                      require(msg.sender == voteDelegate, "!auth");
                      require(_votingAddress == voteOwnership || _votingAddress == voteParameter, "!voteAddr");
                      
                      IStaker(staker).vote(_voteId,_votingAddress,_support);
                      return true;
                  }
              
                  function voteGaugeWeight(address[] calldata _gauge, uint256[] calldata _weight ) external returns(bool){
                      require(msg.sender == voteDelegate, "!auth");
              
                      for(uint256 i = 0; i < _gauge.length; i++){
                          IStaker(staker).voteGaugeWeight(_gauge[i],_weight[i]);
                      }
                      return true;
                  }
              
                  function claimRewards(uint256 _pid, address _gauge) external returns(bool){
                      address stash = poolInfo[_pid].stash;
                      require(msg.sender == stash,"!auth");
              
                      IStaker(staker).claimRewards(_gauge);
                      return true;
                  }
              
                  function setGaugeRedirect(uint256 _pid) external returns(bool){
                      address stash = poolInfo[_pid].stash;
                      require(msg.sender == stash,"!auth");
                      address gauge = poolInfo[_pid].gauge;
                      bytes memory data = abi.encodeWithSelector(bytes4(keccak256("set_rewards_receiver(address)")), stash);
                      IStaker(staker).execute(gauge,uint256(0),data);
                      return true;
                  }
              
                  //claim crv and extra rewards and disperse to reward contracts
                  function _earmarkRewards(uint256 _pid) internal {
                      PoolInfo storage pool = poolInfo[_pid];
                      require(pool.shutdown == false, "pool is closed");
              
                      address gauge = pool.gauge;
              
                      //claim crv
                      IStaker(staker).claimCrv(gauge);
              
                      //check if there are extra rewards
                      address stash = pool.stash;
                      if(stash != address(0)){
                          //claim extra rewards
                          IStash(stash).claimRewards();
                          //process extra rewards
                          IStash(stash).processStash();
                      }
              
                      //crv balance
                      uint256 crvBal = IERC20(crv).balanceOf(address(this));
              
                      if (crvBal > 0) {
                          uint256 _lockIncentive = crvBal.mul(lockIncentive).div(FEE_DENOMINATOR);
                          uint256 _stakerIncentive = crvBal.mul(stakerIncentive).div(FEE_DENOMINATOR);
                          uint256 _callIncentive = crvBal.mul(earmarkIncentive).div(FEE_DENOMINATOR);
                          
                          //send treasury
                          if(treasury != address(0) && treasury != address(this) && platformFee > 0){
                              //only subtract after address condition check
                              uint256 _platform = crvBal.mul(platformFee).div(FEE_DENOMINATOR);
                              crvBal = crvBal.sub(_platform);
                              IERC20(crv).safeTransfer(treasury, _platform);
                          }
              
                          //remove incentives from balance
                          crvBal = crvBal.sub(_lockIncentive).sub(_callIncentive).sub(_stakerIncentive);
              
                          //send incentives for calling
                          IERC20(crv).safeTransfer(msg.sender, _callIncentive);          
              
                          //send crv to lp provider reward contract
                          address rewardContract = pool.crvRewards;
                          IERC20(crv).safeTransfer(rewardContract, crvBal);
                          IRewards(rewardContract).queueNewRewards(crvBal);
              
                          //send lockers' share of crv to reward contract
                          IERC20(crv).safeTransfer(lockRewards, _lockIncentive);
                          IRewards(lockRewards).queueNewRewards(_lockIncentive);
              
                          //send stakers's share of crv to reward contract
                          IERC20(crv).safeTransfer(stakerRewards, _stakerIncentive);
                          IRewards(stakerRewards).queueNewRewards(_stakerIncentive);
                      }
                  }
              
                  function earmarkRewards(uint256 _pid) external returns(bool){
                      require(!isShutdown,"shutdown");
                      _earmarkRewards(_pid);
                      return true;
                  }
              
                  //claim fees from curve distro contract, put in lockers' reward contract
                  function earmarkFees() external returns(bool){
                      //claim fee rewards
                      IStaker(staker).claimFees(feeDistro, feeToken);
                      //send fee rewards to reward contract
                      uint256 _balance = IERC20(feeToken).balanceOf(address(this));
                      IERC20(feeToken).safeTransfer(lockFees, _balance);
                      IRewards(lockFees).queueNewRewards(_balance);
                      return true;
                  }
              
                  //callback from reward contract when crv is received.
                  function rewardClaimed(uint256 _pid, address _address, uint256 _amount) external returns(bool){
                      address rewardContract = poolInfo[_pid].crvRewards;
                      require(msg.sender == rewardContract || msg.sender == lockRewards, "!auth");
              
                      //mint reward tokens
                      ITokenMinter(minter).mint(_address,_amount);
                      
                      return true;
                  }
              
              }

              File 4 of 4: StashTokenWrapper
              // SPDX-License-Identifier: MIT
              pragma solidity 0.6.12;
              import "./interfaces/IBooster.sol";
              import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
              import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
              contract StashTokenWrapper {
                  using SafeERC20 for ERC20;
                  address public constant booster = address(0xF403C135812408BFbE8713b5A23a04b3D48AAE31);
                  address public token;
                  address public rewardPool;
                  bool public isInvalid;
                  constructor() public{}
                  function init(address _token, address _rewardpool) external{
                      require(token == address(0), "init");
                      token = _token;
                      rewardPool = _rewardpool;
                  }
                  function name() external view returns (string memory) {
                      return ERC20(token).name();
                  }
                  function symbol() external view returns (string memory) {
                      return ERC20(token).symbol();
                  }
                  function decimals() external view returns (uint8) {
                      return ERC20(token).decimals();
                  }
                  function totalSupply() public view returns (uint256) {
                      return ERC20(token).balanceOf(address(this));
                  }
                  function balanceOf(address _account) external view returns (uint256) {
                      if(_account == rewardPool){
                          return totalSupply();
                      }
                      return 0;
                  }
                  function transfer(address _recipient, uint256 _amount) external returns (bool) {
                      if(msg.sender == rewardPool){
                          ERC20(token).safeTransfer(_recipient, _amount);
                      }
                      return true;
                  }
                  function setInvalid(bool _isInvalid) external{
                     require(IBooster(booster).owner() == msg.sender, "!owner");
                     isInvalid = _isInvalid;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity 0.6.12;
              interface IBooster {
                  function owner() external view returns(address);
                  function setVoteDelegate(address _voteDelegate) external;
                  function vote(uint256 _voteId, address _votingAddress, bool _support) external returns(bool);
                  function voteGaugeWeight(address[] calldata _gauge, uint256[] calldata _weight ) external returns(bool);
                  function poolInfo(uint256 _pid) external view returns(address _lptoken, address _token, address _gauge, address _crvRewards, address _stash, bool _shutdown);
              }// SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <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 GSN meta-transactions the account sending and
               * paying for execution may not be the actual sender (as far as an application
               * is concerned).
               *
               * This contract is only required for intermediate, library-like contracts.
               */
              abstract contract Context {
                  function _msgSender() internal view virtual returns (address payable) {
                      return msg.sender;
                  }
                  function _msgData() internal view virtual returns (bytes memory) {
                      this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                      return msg.data;
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.2 <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);
                          }
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              import "./IERC20.sol";
              import "../../math/SafeMath.sol";
              import "../../utils/Address.sol";
              /**
               * @title SafeERC20
               * @dev Wrappers around ERC20 operations that throw on failure (when the token
               * contract returns false). Tokens that return no value (and instead revert or
               * throw on failure) are also supported, non-reverting calls are assumed to be
               * successful.
               * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
               * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
               */
              library SafeERC20 {
                  using SafeMath for uint256;
                  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).add(value);
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
                  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                      uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                      _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");
                      }
                  }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <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);
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              import "../../utils/Context.sol";
              import "./IERC20.sol";
              import "../../math/SafeMath.sol";
              /**
               * @dev Implementation of the {IERC20} interface.
               *
               * This implementation is agnostic to the way tokens are created. This means
               * that a supply mechanism has to be added in a derived contract using {_mint}.
               * For a generic mechanism see {ERC20PresetMinterPauser}.
               *
               * TIP: For a detailed writeup see our guide
               * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
               * to implement supply mechanisms].
               *
               * We have followed general OpenZeppelin guidelines: functions revert instead
               * of returning `false` on failure. This behavior is nonetheless conventional
               * and does not conflict with the expectations of ERC20 applications.
               *
               * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
               * This allows applications to reconstruct the allowance for all accounts just
               * by listening to said events. Other implementations of the EIP may not emit
               * these events, as it isn't required by the specification.
               *
               * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
               * functions have been added to mitigate the well-known issues around setting
               * allowances. See {IERC20-approve}.
               */
              contract ERC20 is Context, IERC20 {
                  using SafeMath for uint256;
                  mapping (address => uint256) private _balances;
                  mapping (address => mapping (address => uint256)) private _allowances;
                  uint256 private _totalSupply;
                  string private _name;
                  string private _symbol;
                  uint8 private _decimals;
                  /**
                   * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                   * a default value of 18.
                   *
                   * To select a different value for {decimals}, use {_setupDecimals}.
                   *
                   * All three of these values are immutable: they can only be set once during
                   * construction.
                   */
                  constructor (string memory name_, string memory symbol_) public {
                      _name = name_;
                      _symbol = symbol_;
                      _decimals = 18;
                  }
                  /**
                   * @dev Returns the name of the token.
                   */
                  function name() public view virtual returns (string memory) {
                      return _name;
                  }
                  /**
                   * @dev Returns the symbol of the token, usually a shorter version of the
                   * name.
                   */
                  function symbol() public view virtual 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 virtual returns (uint8) {
                      return _decimals;
                  }
                  /**
                   * @dev See {IERC20-totalSupply}.
                   */
                  function totalSupply() public view virtual override returns (uint256) {
                      return _totalSupply;
                  }
                  /**
                   * @dev See {IERC20-balanceOf}.
                   */
                  function balanceOf(address account) public view virtual override returns (uint256) {
                      return _balances[account];
                  }
                  /**
                   * @dev See {IERC20-transfer}.
                   *
                   * Requirements:
                   *
                   * - `recipient` cannot be the zero address.
                   * - the caller must have a balance of at least `amount`.
                   */
                  function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                      _transfer(_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;
                  }
                  /**
                   * @dev See {IERC20-transferFrom}.
                   *
                   * Emits an {Approval} event indicating the updated allowance. This is not
                   * required by the EIP. See the note at the beginning of {ERC20}.
                   *
                   * Requirements:
                   *
                   * - `sender` and `recipient` cannot be the zero address.
                   * - `sender` must have a balance of at least `amount`.
                   * - the caller must have allowance for ``sender``'s tokens of at least
                   * `amount`.
                   */
                  function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                      _transfer(sender, recipient, amount);
                      _approve(sender, _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 virtual {
                      _decimals = decimals_;
                  }
                  /**
                   * @dev Hook that is called before any transfer of tokens. This includes
                   * minting and burning.
                   *
                   * Calling conditions:
                   *
                   * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                   * will be to transferred to `to`.
                   * - when `from` is zero, `amount` tokens will be minted for `to`.
                   * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                   * - `from` and `to` are never both zero.
                   *
                   * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                   */
                  function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
              }
              // SPDX-License-Identifier: MIT
              pragma solidity >=0.6.0 <0.8.0;
              /**
               * @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;
                  }
              }