ETH Price: $2,069.27 (+0.93%)

Transaction Decoder

Block:
24059991 at Dec-21-2025 09:09:35 AM +UTC
Transaction Fee:
0.000003606326450132 ETH $0.007462
Gas Used:
89,948 Gas / 0.040093459 Gwei

Emitted Events:

704 CowProtocolVirtualToken.Vested( user=0xDAAe26e391e414C2693798918483283eA9514d3F, amount=202394883457346198 )
705 CowProtocolToken.Transfer( from=CowProtocolVirtualToken, to=0xDAAe26e391e414C2693798918483283eA9514d3F, value=202394883457346198 )
706 CowProtocolVirtualToken.Transfer( from=0xDAAe26e391e414C2693798918483283eA9514d3F, to=0x0000000000000000000000000000000000000000, value=202394883457346198 )
707 0xdaae26e391e414c2693798918483283ea9514d3f.0x6eb7af0fe8761c066484ab6b41c49a1eecb9025e21f258e3e7f0ef3631d67b4a( 0x6eb7af0fe8761c066484ab6b41c49a1eecb9025e21f258e3e7f0ef3631d67b4a, 000000000000000000000000d057b63f5e69cf1b929b356b579cba08d7688048, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000004, 3e9ffbea00000000000000000000000000000000000000000000000000000000 )
708 CowProtocolToken.Transfer( from=0xDAAe26e391e414C2693798918483283eA9514d3F, to=[Sender] 0x164dc5333938299b6db62f73b63f8270ff3892c2, value=199766378477380663 )
709 0xdaae26e391e414c2693798918483283ea9514d3f.0x6eb7af0fe8761c066484ab6b41c49a1eecb9025e21f258e3e7f0ef3631d67b4a( 0x6eb7af0fe8761c066484ab6b41c49a1eecb9025e21f258e3e7f0ef3631d67b4a, 000000000000000000000000def1ca1fb7fbcdc777520aa7f396b4e015f497ab, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000000000000000000000000000000000000000000044, a9059cbb000000000000000000000000164dc5333938299b6db62f73b63f8270, ff3892c200000000000000000000000000000000000000000000000002c5b676, 7b35e43700000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x164Dc533...0ff3892c2
0.759223749087753818 Eth
Nonce: 20194
0.759220142761303686 Eth
Nonce: 20195
0.000003606326450132
0xD057B63f...8D7688048
(BuilderNet)
142.452718560974312117 Eth142.452718560974492013 Eth0.000000000000179896
0xDEf1CA1f...015F497aB

Execution Trace

0x88a0a851b28018ac9bda57ced6a95c8efc7b73f8.09c5eabe( )
  • 0xdaae26e391e414c2693798918483283ea9514d3f.bca8c7b5( )
    • CowProtocolVirtualToken.CALL( )
      • CowProtocolToken.transfer( recipient=0xDAAe26e391e414C2693798918483283eA9514d3F, amount=202394883457346198 ) => ( True )
      • CowProtocolToken.balanceOf( account=0x164Dc5333938299B6db62f73b63f8270ff3892c2 ) => ( 642921804079650009159 )
      • 0xdaae26e391e414c2693798918483283ea9514d3f.bca8c7b5( )
        • CowProtocolToken.transfer( recipient=0x164Dc5333938299B6db62f73b63f8270ff3892c2, amount=199766378477380663 ) => ( True )
        • CowProtocolToken.balanceOf( account=0x164Dc5333938299B6db62f73b63f8270ff3892c2 ) => ( 643121570458127389822 )
          File 1 of 2: CowProtocolVirtualToken
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "./mixins/NonTransferrableErc20.sol";
          import "./mixins/Vesting.sol";
          import "./mixins/Claiming.sol";
          import "./mixins/MerkleDistributor.sol";
          import "./vendored/mixins/StorageAccessible.sol";
          /// @dev The token that manages how the CoW Protocol governance token is
          /// distributed to all different types of investors.
          /// @title CoW Protocol Virtual Token
          /// @author CoW Protocol Developers
          contract CowProtocolVirtualToken is
              NonTransferrableErc20,
              Vesting,
              Claiming,
              MerkleDistributor,
              StorageAccessible
          {
              string private constant ERC20_SYMBOL = "vCOW";
              string private constant ERC20_NAME = "CoW Protocol Virtual Token";
              constructor(
                  bytes32 merkleRoot,
                  address cowToken,
                  address payable communityFundsTarget,
                  address investorFundsTarget,
                  address usdcToken,
                  uint256 usdcPrice,
                  address gnoToken,
                  uint256 gnoPrice,
                  address wrappedNativeToken,
                  uint256 nativeTokenPrice,
                  address teamController
              )
                  NonTransferrableErc20(ERC20_NAME, ERC20_SYMBOL)
                  Claiming(
                      cowToken,
                      communityFundsTarget,
                      investorFundsTarget,
                      usdcToken,
                      usdcPrice,
                      gnoToken,
                      gnoPrice,
                      wrappedNativeToken,
                      nativeTokenPrice,
                      teamController
                  )
                  MerkleDistributor(merkleRoot)
              // solhint-disable-next-line no-empty-blocks
              {
              }
              /// @dev Returns the sum of tokens that are either held as
              /// instantlySwappableBalance or will be vested in the future
              /// @param user The user for whom the balance is calculated
              /// @return Balance of the user
              function balanceOf(address user) public view returns (uint256) {
                  return
                      instantlySwappableBalance[user] +
                      fullAllocation[user] -
                      vestedAllocation[user];
              }
              /// @dev Returns the balance of a user assuming all vested tokens would
              /// have been converted into virtual tokens
              /// @param user The user for whom the balance is calculated
              /// @return Balance the user would have after calling `swapAll`
              function swappableBalanceOf(address user) public view returns (uint256) {
                  return instantlySwappableBalance[user] + newlyVestedBalance(user);
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "../vendored/interfaces/IERC20.sol";
          /// @dev A contract of an ERC20 token that cannot be transferred.
          /// @title Non-Transferrable ERC20
          /// @author CoW Protocol Developers
          abstract contract NonTransferrableErc20 is IERC20 {
              /// @dev The ERC20 name of the token
              string public name;
              /// @dev The ERC20 symbol of the token
              string public symbol;
              /// @dev The ERC20 number of decimals of the token
              uint8 public constant decimals = 18; // solhint-disable const-name-snakecase
              // solhint-disable-next-line no-empty-blocks
              constructor(string memory _name, string memory _symbol) {
                  name = _name;
                  symbol = _symbol;
              }
              /// @dev This error is fired when trying to perform an action that is not
              /// supported by the contract, like transfers and approvals. These actions
              /// will never be supported.
              error NotSupported();
              /// @dev All types of transfers are permanently disabled.
              function transferFrom(
                  address,
                  address,
                  uint256
              ) public pure returns (bool) {
                  revert NotSupported();
              }
              /// @dev All types of transfers are permanently disabled.
              function transfer(address, uint256) public pure returns (bool) {
                  revert NotSupported();
              }
              /// @dev All types of approvals are permanently disabled to reduce code
              /// size.
              function approve(address, uint256) public pure returns (bool) {
                  revert NotSupported();
              }
              /// @dev Approvals cannot be set, so allowances are always zero.
              function allowance(address, address) public pure returns (uint256) {
                  return 0;
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "../vendored/libraries/Math.sol";
          import "../interfaces/VestingInterface.sol";
          /// @dev The vesting logic for distributing the COW token
          /// @title Vesting Logic
          /// @author CoW Protocol Developers
          contract Vesting is VestingInterface {
              /// @dev The timestamp of the official vesting start. This value is shared
              /// between all participants.
              uint256 public immutable vestingStart;
              /// @dev How long it will take for all vesting to be completed. It is set to
              /// four years.
              uint256 public constant VESTING_PERIOD_IN_SECONDS = 4 * 365 days + 1 days;
              /// @dev Stores the amount of vesting that the user has already vested.
              mapping(address => uint256) public vestedAllocation;
              /// @dev Stores the maximum amount of vesting available to each user. This
              /// is exactly the total amount of vesting that can be converted after the
              /// vesting period is completed.
              mapping(address => uint256) public fullAllocation;
              /// @dev Stores a bit indicating whether a vesting is cancelable
              /// Important: This implementaiton implies that there can not be a
              /// cancelable and non-cancelable vesting in parallel
              mapping(address => bool) public isCancelable;
              /// @dev Event emitted when a new vesting position is added. The amount is
              /// the additional amount that can be vested at the end of the
              /// claiming period.
              event VestingAdded(address indexed user, uint256 amount, bool isCancelable);
              /// @dev Event emitted when a vesting position is canceled. The amount is
              /// the number of remaining vesting that will be given to the beneficiary.
              event VestingStopped(
                  address indexed user,
                  address freedVestingBeneficiary,
                  uint256 amount
              );
              /// @dev Event emitted when the users claims (also partially) a vesting
              /// position.
              event Vested(address indexed user, uint256 amount);
              /// @dev Error returned when trying to stop a claim that is not cancelable.
              error VestingNotCancelable();
              constructor() {
                  vestingStart = block.timestamp; // solhint-disable-line not-rely-on-time
              }
              /// @inheritdoc VestingInterface
              function addVesting(
                  address user,
                  uint256 vestingAmount,
                  bool isCancelableFlag
              ) internal override {
                  if (isCancelableFlag) {
                      // if one cancelable vesting is made, it converts all vestings into cancelable ones
                      isCancelable[user] = isCancelableFlag;
                  }
                  fullAllocation[user] += vestingAmount;
                  emit VestingAdded(user, vestingAmount, isCancelableFlag);
              }
              /// @inheritdoc VestingInterface
              function shiftVesting(address user, address freedVestingBeneficiary)
                  internal
                  override
                  returns (uint256 accruedVesting)
              {
                  if (!isCancelable[user]) {
                      revert VestingNotCancelable();
                  }
                  accruedVesting = vest(user);
                  uint256 userFullAllocation = fullAllocation[user];
                  uint256 userVestedAllocation = vestedAllocation[user];
                  fullAllocation[user] = 0;
                  vestedAllocation[user] = 0;
                  fullAllocation[freedVestingBeneficiary] += userFullAllocation;
                  vestedAllocation[freedVestingBeneficiary] += userVestedAllocation;
                  emit VestingStopped(
                      user,
                      freedVestingBeneficiary,
                      userFullAllocation - userVestedAllocation
                  );
              }
              /// @inheritdoc VestingInterface
              function vest(address user)
                  internal
                  override
                  returns (uint256 newlyVested)
              {
                  newlyVested = newlyVestedBalance(user);
                  vestedAllocation[user] += newlyVested;
                  emit Vested(user, newlyVested);
              }
              /// @dev Assuming no conversions has been done by the user, calculates how
              /// much vesting can be converted at this point in time.
              /// @param user The user for whom the result is being calculated.
              /// @return How much vesting can be converted if no conversions had been
              /// done before.
              function cumulativeVestedBalance(address user)
                  public
                  view
                  returns (uint256)
              {
                  return
                      (Math.min(
                          block.timestamp - vestingStart, // solhint-disable-line not-rely-on-time
                          VESTING_PERIOD_IN_SECONDS
                      ) * fullAllocation[user]) / (VESTING_PERIOD_IN_SECONDS);
              }
              /// @dev Calculates how much vesting can be converted at this point in time.
              /// Unlike `cumulativeVestedBalance`, this function keeps track of previous
              /// conversions.
              /// @param user The user for whom the result is being calculated.
              /// @return How much vesting can be converted.
              function newlyVestedBalance(address user) public view returns (uint256) {
                  return cumulativeVestedBalance(user) - vestedAllocation[user];
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "../vendored/interfaces/IERC20.sol";
          import "../vendored/libraries/SafeERC20.sol";
          import "../interfaces/ClaimingInterface.sol";
          import "../interfaces/VestingInterface.sol";
          /// @dev The logic behind the claiming of virtual tokens and the swapping to
          /// real tokens.
          /// @title COW Virtual Token Claiming Logic
          /// @author CoW Protocol Developers
          abstract contract Claiming is ClaimingInterface, VestingInterface, IERC20 {
              using SafeERC20 for IERC20;
              /// @dev Prices are represented as fractions. For readability, the
              /// denominator is one unit of the virtual token (assuming it has 18
              /// decimals), in this way the numerator of a price is the number of atoms
              /// that have the same value as a unit of virtual token.
              uint256 internal constant PRICE_DENOMINATOR = 10**18;
              /// @dev Price numerator for the COW/USDC price. This is the number of USDC
              /// atoms required to obtain a full unit of virtual token from an option.
              uint256 public immutable usdcPrice;
              /// @dev Price numerator for the COW/GNO price. This is the number of GNO
              /// atoms required to obtain a full unit of virtual token from an option.
              uint256 public immutable gnoPrice;
              /// @dev Price numerator for the COW/native-token price. This is the number
              /// of native token wei required to obtain a full unit of virtual token from
              /// an option.
              uint256 public immutable nativeTokenPrice;
              /// @dev The proceeds from selling options to the community will be sent to,
              /// this address.
              address payable public immutable communityFundsTarget;
              /// @dev All proceeds from known investors will be sent to this address.
              address public immutable investorFundsTarget;
              /// @dev Address of the real COW token. Tokens claimed by this contract can
              /// be converted to this token if this contract stores some balance of it.
              IERC20 public immutable cowToken;
              /// @dev Address of the USDC token. It is a form of payment for investors.
              IERC20 public immutable usdcToken;
              /// @dev Address of the GNO token. It is a form of payment for users who
              /// claim the options derived from holding GNO.
              IERC20 public immutable gnoToken;
              /// @dev Address of the wrapped native token. It is a form of payment for
              /// users who claim the options derived from being users of the CoW
              /// Protocol.
              IERC20 public immutable wrappedNativeToken;
              /// @dev Address representing the CoW Protocol/CowSwap team. It is the only
              /// address that is allowed to stop the vesting of a claim, and exclusively
              /// for team claims.
              address public immutable teamController;
              /// @dev Time at which this contract was deployed.
              uint256 public immutable deploymentTimestamp;
              /// @dev Returns the amount of virtual tokens in existence, including those
              /// that have yet to be vested.
              uint256 public totalSupply;
              /// @dev How many tokens can be immediately swapped in exchange for real
              /// tokens for each user.
              mapping(address => uint256) public instantlySwappableBalance;
              /// @dev Error presented to a user trying to claim virtual tokens after the
              /// claiming period has ended.
              error ClaimingExpired();
              /// @dev Error presented to anyone but the team controller to stop a
              /// cancelable vesting position (i.e., only team vesting).
              error OnlyTeamController();
              /// @dev Error resulting from sending an incorrect amount of native to the
              /// contract.
              error InvalidNativeTokenAmount();
              /// @dev Error caused by an unsuccessful attempt to transfer native tokens.
              error FailedNativeTokenTransfer();
              /// @dev Error resulting from sending native tokens for a claim that cannot
              /// be redeemed with native tokens.
              error CannotSendNativeToken();
              constructor(
                  address _cowToken,
                  address payable _communityFundsTarget,
                  address _investorFundsTarget,
                  address _usdcToken,
                  uint256 _usdcPrice,
                  address _gnoToken,
                  uint256 _gnoPrice,
                  address _wrappedNativeToken,
                  uint256 _nativeTokenPrice,
                  address _teamController
              ) {
                  cowToken = IERC20(_cowToken);
                  communityFundsTarget = _communityFundsTarget;
                  investorFundsTarget = _investorFundsTarget;
                  usdcToken = IERC20(_usdcToken);
                  usdcPrice = _usdcPrice;
                  gnoToken = IERC20(_gnoToken);
                  gnoPrice = _gnoPrice;
                  wrappedNativeToken = IERC20(_wrappedNativeToken);
                  nativeTokenPrice = _nativeTokenPrice;
                  teamController = _teamController;
                  // solhint-disable-next-line not-rely-on-time
                  deploymentTimestamp = block.timestamp;
              }
              /// @dev Allows the decorated function only to be executed before the
              /// contract deployment date plus the input amount of seconds.
              /// @param durationSinceDeployment Number of seconds after contract
              /// deployment before which the function can be executed anymore. The
              /// function reverts afterwards.
              modifier before(uint256 durationSinceDeployment) {
                  // solhint-disable-next-line not-rely-on-time
                  if (block.timestamp > deploymentTimestamp + durationSinceDeployment) {
                      revert ClaimingExpired();
                  }
                  _;
              }
              /// @dev The decorated function can only be executed by the team controller.
              modifier onlyTeamController() {
                  if (msg.sender != teamController) {
                      revert OnlyTeamController();
                  }
                  _;
              }
              /// @inheritdoc ClaimingInterface
              function performClaim(
                  ClaimType claimType,
                  address payer,
                  address claimant,
                  uint256 amount,
                  uint256 sentNativeTokens
              ) internal override {
                  if (claimType == ClaimType.Airdrop) {
                      claimAirdrop(claimant, amount, sentNativeTokens);
                  } else if (claimType == ClaimType.GnoOption) {
                      claimGnoOption(claimant, amount, payer, sentNativeTokens);
                  } else if (claimType == ClaimType.UserOption) {
                      claimUserOption(claimant, amount, payer, sentNativeTokens);
                  } else if (claimType == ClaimType.Investor) {
                      claimInvestor(claimant, amount, payer, sentNativeTokens);
                  } else if (claimType == ClaimType.Team) {
                      claimTeam(claimant, amount, sentNativeTokens);
                  } else {
                      // claimType == ClaimType.Advisor
                      claimAdvisor(claimant, amount, sentNativeTokens);
                  }
                  // Each claiming operation results in the creation of `amount` virtual
                  // tokens.
                  totalSupply += amount;
                  emit Transfer(address(0), claimant, amount);
              }
              /// @dev Stops all vesting claims of a user. This is only applicable for
              /// claims that are cancellable, i.e., team claims.
              /// @param user The user whose vesting claims should be canceled.
              function stopClaim(address user) external onlyTeamController {
                  uint256 accruedVesting = shiftVesting(user, teamController);
                  instantlySwappableBalance[user] += accruedVesting;
              }
              /// @dev Transfers all ETH stored in the contract to the community funds
              // target.
              function withdrawEth() external {
                  // We transfer ETH using .call instead of .transfer as not to restrict
                  // the amount of gas sent to the target address during the transfer.
                  // This is particularly relevant for sending ETH to smart contracts:
                  // since EIP 2929, if a contract sends eth using `.transfer` then the
                  // transaction proposed to the node needs to specify an _access list_,
                  // which is currently not well supported by some wallet implementations.
                  // There is no reentrancy risk as this call does not touch any storage
                  // slot and the contract balance is not used in other logic.
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, ) = communityFundsTarget.call{
                      value: address(this).balance
                  }("");
                  if (!success) {
                      revert FailedNativeTokenTransfer();
                  }
              }
              /// @dev Performs an airdrop-type claim for the user.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimAirdrop(
                  address account,
                  uint256 amount,
                  uint256 sentNativeTokens
              ) private before(6 weeks) {
                  if (sentNativeTokens != 0) {
                      revert CannotSendNativeToken();
                  }
                  instantlySwappableBalance[account] += amount;
              }
              /// @dev Claims a Gno option for the user.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user after vesting.
              /// @param payer The address that pays the amount required by the claim.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimGnoOption(
                  address account,
                  uint256 amount,
                  address payer,
                  uint256 sentNativeTokens
              ) private before(2 weeks) {
                  if (sentNativeTokens != 0) {
                      revert CannotSendNativeToken();
                  }
                  collectPayment(gnoToken, gnoPrice, payer, communityFundsTarget, amount);
                  addVesting(account, amount, false);
              }
              /// @dev Claims a native-token-based option for the user.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user after vesting.
              /// @param payer The address that pays the amount required by the claim.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimUserOption(
                  address account,
                  uint256 amount,
                  address payer,
                  uint256 sentNativeTokens
              ) private before(2 weeks) {
                  if (sentNativeTokens != 0) {
                      collectNativeTokenPayment(amount, sentNativeTokens);
                  } else {
                      collectPayment(
                          wrappedNativeToken,
                          nativeTokenPrice,
                          payer,
                          communityFundsTarget,
                          amount
                      );
                  }
                  addVesting(account, amount, false);
              }
              /// @dev Claims an investor option.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user after vesting.
              /// @param payer The address that pays the amount required by the claim.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimInvestor(
                  address account,
                  uint256 amount,
                  address payer,
                  uint256 sentNativeTokens
              ) private before(2 weeks) {
                  if (sentNativeTokens != 0) {
                      revert CannotSendNativeToken();
                  }
                  collectPayment(
                      usdcToken,
                      usdcPrice,
                      payer,
                      investorFundsTarget,
                      amount
                  );
                  addVesting(account, amount, false);
              }
              /// @dev Claims a team option. Team options are granted without any payment
              /// but can be canceled.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user after vesting.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimTeam(
                  address account,
                  uint256 amount,
                  uint256 sentNativeTokens
              ) private before(6 weeks) {
                  if (sentNativeTokens != 0) {
                      revert CannotSendNativeToken();
                  }
                  addVesting(account, amount, true);
              }
              /// @dev Claims an adviser option. Team options are granted without any
              /// payment and cannot be canceled.
              /// @param account The user for which the claim is performed.
              /// @param amount The full amount claimed by the user after vesting.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function claimAdvisor(
                  address account,
                  uint256 amount,
                  uint256 sentNativeTokens
              ) private before(6 weeks) {
                  if (sentNativeTokens != 0) {
                      revert CannotSendNativeToken();
                  }
                  addVesting(account, amount, false);
              }
              /// @dev Executes a transfer from the user to the target. The transfered
              /// amount is based on the input COW price and amount of COW bought.
              /// @param token The token used for the payment.
              /// @param price The number of atoms of the input token that are equivalent
              /// to one atom of COW multiplied by PRICE_DENOMINATOR.
              /// @param from The address from which to take the funds.
              /// @param to The address to which to send the funds.
              /// @param amount The amount of COW atoms that will be paid for.
              function collectPayment(
                  IERC20 token,
                  uint256 price,
                  address from,
                  address to,
                  uint256 amount
              ) private {
                  uint256 tokenEquivalent = convertCowAmountAtPrice(amount, price);
                  token.safeTransferFrom(from, to, tokenEquivalent);
              }
              /// @dev Transfers native tokens from this contract to the target, assuming
              /// that the amount of native tokens sent coincides with the expected amount
              /// of native tokens. This amount is based on the price of the native token
              /// and amount of COW bought.
              /// @param amount The amount of COW atoms that will be paid for.
              /// @param sentNativeTokens Amount of ETH sent along to the transaction.
              function collectNativeTokenPayment(uint256 amount, uint256 sentNativeTokens)
                  private
                  view
              {
                  uint256 nativeTokenEquivalent = convertCowAmountAtPrice(
                      amount,
                      nativeTokenPrice
                  );
                  if (sentNativeTokens != nativeTokenEquivalent) {
                      revert InvalidNativeTokenAmount();
                  }
              }
              /// @dev Converts input amount in COW token atoms to an amount in token
              /// atoms at the specified price.
              /// @param amount Amount of tokens to convert.
              /// @param price The number of atoms of the input token that are equivalent
              /// to one atom of COW *multiplied by PRICE_DENOMINATOR*.
              function convertCowAmountAtPrice(uint256 amount, uint256 price)
                  private
                  pure
                  returns (uint256)
              {
                  return (amount * price) / PRICE_DENOMINATOR;
              }
              /// @dev Converts an amount of (virtual) tokens from this contract to real
              /// tokens based on the claims previously performed by the caller.
              /// @param amount How many virtual tokens to convert into real tokens.
              function swap(uint256 amount) external {
                  makeVestingSwappable();
                  _swap(amount);
              }
              /// @dev Converts all available (virtual) tokens from this contract to real
              /// tokens based on the claims previously performed by the caller.
              /// @return swappedBalance The full amount that was swapped (i.e., virtual
              /// tokens burnt as well as real tokens received).
              function swapAll() external returns (uint256 swappedBalance) {
                  swappedBalance = makeVestingSwappable();
                  _swap(swappedBalance);
              }
              /// @dev Transfers real tokens to the message sender and reduces the balance
              /// of virtual tokens available. Note that this function assumes that the
              /// current contract stores enough real tokens to fulfill this swap request.
              /// @param amount How many virtual tokens to convert into real tokens.
              function _swap(uint256 amount) private {
                  instantlySwappableBalance[msg.sender] -= amount;
                  totalSupply -= amount;
                  cowToken.safeTransfer(msg.sender, amount);
                  emit Transfer(msg.sender, address(0), amount);
              }
              /// @dev Adds the currently vested amount to the immediately swappable
              /// balance.
              /// @return swappableBalance The maximum balance that can be swapped at
              /// this point in time by the caller.
              function makeVestingSwappable() private returns (uint256 swappableBalance) {
                  swappableBalance =
                      instantlySwappableBalance[msg.sender] +
                      vest(msg.sender);
                  instantlySwappableBalance[msg.sender] = swappableBalance;
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          // This contract is based on Uniswap's MekleDistributor, which can be found at:
          // https://github.com/Uniswap/merkle-distributor/blob/0d478d722da2e5d95b7292fd8cbdb363d98e9a93/contracts/MerkleDistributor.sol
          //
          // The changes between the original contract and this are:
          //  - the claim function doesn't trigger a transfer on a successful proof, but
          //    it executes a dedicated (virtual) function.
          //  - added a claimMany function for bundling multiple claims in a transaction
          //  - supported sending an amount of native tokens along with the claim
          //  - added the option of claiming less than the maximum amount
          //  - gas optimizations in the packing and unpacking of the claimed bit
          //  - bumped Solidity version
          //  - code formatting
          pragma solidity ^0.8.10;
          import "../vendored/interfaces/IERC20.sol";
          import "../vendored/libraries/MerkleProof.sol";
          import "../interfaces/ClaimingInterface.sol";
          abstract contract MerkleDistributor is ClaimingInterface {
              bytes32 public immutable merkleRoot;
              /// @dev Event fired if a claim was successfully performed.
              event Claimed(
                  uint256 index,
                  ClaimType claimType,
                  address claimant,
                  uint256 claimableAmount,
                  uint256 claimedAmount
              );
              /// @dev Error caused by a user trying to call the claim function for a
              /// claim that has already been used before.
              error AlreadyClaimed();
              /// @dev Error caused by a user trying to claim a larger amount than the
              /// maximum allowed in the claim.
              error ClaimingMoreThanMaximum();
              /// @dev Error caused by the caller trying to perform a partial claim while
              /// not being the owner of the claim.
              error OnlyOwnerCanClaimPartially();
              /// @dev Error caused by calling the claim function with an invalid proof.
              error InvalidProof();
              /// @dev Error caused by calling claimMany with a transaction value that is
              /// different from the required one.
              error InvalidNativeTokenValue();
              /// @dev Packed array of booleans that stores if a claim is available.
              mapping(uint256 => uint256) private claimedBitMap;
              constructor(bytes32 merkleRoot_) {
                  merkleRoot = merkleRoot_;
              }
              /// @dev Checks if the claim at the provided index has already been claimed.
              /// @param index The index to check.
              /// @return Whether the claim at the given index has already been claimed.
              function isClaimed(uint256 index) public view returns (bool) {
                  uint256 claimedWordIndex = index >> 8;
                  uint256 claimedBitIndex = index & 0xff;
                  uint256 claimedWord = claimedBitMap[claimedWordIndex];
                  uint256 mask = (1 << claimedBitIndex);
                  return claimedWord & mask != 0;
              }
              /// @dev Mark the provided index as having been claimed.
              /// @param index The index that was claimed.
              function _setClaimed(uint256 index) private {
                  uint256 claimedWordIndex = index >> 8;
                  uint256 claimedBitIndex = index & 0xff;
                  claimedBitMap[claimedWordIndex] =
                      claimedBitMap[claimedWordIndex] |
                      (1 << claimedBitIndex);
              }
              /// @dev This function verifies the provided input proof based on the
              /// provided input. If the proof is valid, the function [`performClaim`] is
              /// called for the claimed amount.
              /// @param index The index that identifies the input claim.
              /// @param claimType See [`performClaim`].
              /// @param claimant See [`performClaim`].
              /// @param claimableAmount The maximum amount that the claimant can claim
              /// for this claim. Should not be smaller than claimedAmount.
              /// @param claimedAmount See [`performClaim`].
              /// @param merkleProof A proof that the input claim belongs to the unique
              /// Merkle root associated to this contract.
              function claim(
                  uint256 index,
                  ClaimType claimType,
                  address claimant,
                  uint256 claimableAmount,
                  uint256 claimedAmount,
                  bytes32[] calldata merkleProof
              ) external payable {
                  _claim(
                      index,
                      claimType,
                      claimant,
                      claimableAmount,
                      claimedAmount,
                      merkleProof,
                      msg.value
                  );
              }
              /// @dev This function verifies and executes multiple claims in the same
              /// transaction.
              /// @param indices A vector of indices. See [`claim`] for details.
              /// @param claimTypes A vector of claim types. See [`performClaim`] for
              /// details.
              /// @param claimants A vector of claimants. See [`performClaim`] for
              /// details.
              /// @param claimableAmounts A vector of claimable amounts. See [`claim`] for
              /// details.
              /// @param claimedAmounts A vector of claimed amounts. See [`performClaim`]
              /// for details.
              /// @param merkleProofs A vector of merkle proofs. See [`claim`] for
              /// details.
              /// @param sentNativeTokens A vector of native token amounts. See
              /// [`performClaim`] for details.
              function claimMany(
                  uint256[] memory indices,
                  ClaimType[] memory claimTypes,
                  address[] calldata claimants,
                  uint256[] calldata claimableAmounts,
                  uint256[] calldata claimedAmounts,
                  bytes32[][] calldata merkleProofs,
                  uint256[] calldata sentNativeTokens
              ) external payable {
                  uint256 sumSentNativeTokens;
                  for (uint256 i = 0; i < indices.length; i++) {
                      sumSentNativeTokens += sentNativeTokens[i];
                      _claim(
                          indices[i],
                          claimTypes[i],
                          claimants[i],
                          claimableAmounts[i],
                          claimedAmounts[i],
                          merkleProofs[i],
                          sentNativeTokens[i]
                      );
                  }
                  if (sumSentNativeTokens != msg.value) {
                      revert InvalidNativeTokenValue();
                  }
              }
              /// @dev This function verifies the provided input proof based on the
              /// provided input. If the proof is valid, the function [`performClaim`] is
              /// called for the claimed amount.
              /// @param index See [`claim`].
              /// @param claimType See [`performClaim`].
              /// @param claimant See [`performClaim`].
              /// @param claimableAmount See [`claim`].
              /// @param claimedAmount See [`performClaim`].
              /// @param merkleProof See [`claim`].
              /// @param sentNativeTokens See [`performClaim`].
              function _claim(
                  uint256 index,
                  ClaimType claimType,
                  address claimant,
                  uint256 claimableAmount,
                  uint256 claimedAmount,
                  bytes32[] calldata merkleProof,
                  uint256 sentNativeTokens
              ) private {
                  if (isClaimed(index)) {
                      revert AlreadyClaimed();
                  }
                  if (claimedAmount > claimableAmount) {
                      revert ClaimingMoreThanMaximum();
                  }
                  if ((claimedAmount < claimableAmount) && (msg.sender != claimant)) {
                      revert OnlyOwnerCanClaimPartially();
                  }
                  // Note: all types used inside `encodePacked` should have fixed length,
                  // otherwise the same proof could be used in different claims.
                  bytes32 node = keccak256(
                      abi.encodePacked(index, claimType, claimant, claimableAmount)
                  );
                  if (!MerkleProof.verify(merkleProof, merkleRoot, node)) {
                      revert InvalidProof();
                  }
                  _setClaimed(index);
                  performClaim(
                      claimType,
                      msg.sender,
                      claimant,
                      claimedAmount,
                      sentNativeTokens
                  );
                  emit Claimed(
                      index,
                      claimType,
                      claimant,
                      claimableAmount,
                      claimedAmount
                  );
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-only
          // Vendored from Gnosis utility contracts, see:
          // <https://raw.githubusercontent.com/gnosis/gp-v2-contracts/40c349d52d14f8f3c9f787fe2fca5a496bb10ea9/src/contracts/mixins/StorageAccessible.sol>
          // The following changes were made:
          // - Modified Solidity version
          // - Formatted code
          pragma solidity ^0.8.10;
          /// @title ViewStorageAccessible - Interface on top of StorageAccessible base class to allow simulations from view functions
          interface ViewStorageAccessible {
              /**
               * @dev Same as `simulateDelegatecall` on StorageAccessible. Marked as view so that it can be called from external contracts
               * that want to run simulations from within view functions. Will revert if the invoked simulation attempts to change state.
               */
              function simulateDelegatecall(
                  address targetContract,
                  bytes memory calldataPayload
              ) external view returns (bytes memory);
              /**
               * @dev Same as `getStorageAt` on StorageAccessible. This method allows reading aribtrary ranges of storage.
               */
              function getStorageAt(uint256 offset, uint256 length)
                  external
                  view
                  returns (bytes memory);
          }
          /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
          contract StorageAccessible {
              /**
               * @dev Reads `length` bytes of storage in the currents contract
               * @param offset - the offset in the current contract's storage in words to start reading from
               * @param length - the number of words (32 bytes) of data to read
               * @return the bytes that were read.
               */
              function getStorageAt(uint256 offset, uint256 length)
                  external
                  view
                  returns (bytes memory)
              {
                  bytes memory result = new bytes(length * 32);
                  for (uint256 index = 0; index < length; index++) {
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let word := sload(add(offset, index))
                          mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                      }
                  }
                  return result;
              }
              /**
               * @dev Performs a delegetecall on a targetContract in the context of self.
               * Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result as bytes.
               * @param targetContract Address of the contract containing the code to execute.
               * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
               */
              function simulateDelegatecall(
                  address targetContract,
                  bytes memory calldataPayload
              ) public returns (bytes memory response) {
                  bytes memory innerCall = abi.encodeWithSelector(
                      this.simulateDelegatecallInternal.selector,
                      targetContract,
                      calldataPayload
                  );
                  // solhint-disable-next-line avoid-low-level-calls
                  (, response) = address(this).call(innerCall);
                  bool innerSuccess = response[response.length - 1] == 0x01;
                  setLength(response, response.length - 1);
                  if (innerSuccess) {
                      return response;
                  } else {
                      revertWith(response);
                  }
              }
              /**
               * @dev Performs a delegetecall on a targetContract in the context of self.
               * Internally reverts execution to avoid side effects (making it static). Returns encoded result as revert message
               * concatenated with the success flag of the inner call as a last byte.
               * @param targetContract Address of the contract containing the code to execute.
               * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
               */
              function simulateDelegatecallInternal(
                  address targetContract,
                  bytes memory calldataPayload
              ) external returns (bytes memory response) {
                  bool success;
                  // solhint-disable-next-line avoid-low-level-calls
                  (success, response) = targetContract.delegatecall(calldataPayload);
                  revertWith(abi.encodePacked(response, success));
              }
              function revertWith(bytes memory response) internal pure {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      revert(add(response, 0x20), mload(response))
                  }
              }
              function setLength(bytes memory buffer, uint256 length) internal pure {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      mstore(buffer, length)
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/IERC20.sol>
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC20 standard as defined in the EIP.
           */
          interface IERC20 {
              /**
               * @dev Returns the amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `recipient`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address recipient, uint256 amount)
                  external
                  returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender)
                  external
                  view
                  returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `sender` to `recipient` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address sender,
                  address recipient,
                  uint256 amount
              ) external returns (bool);
              /**
               * @dev Emitted when `value` tokens are moved from one account (`from`) to
               * another (`to`).
               *
               * Note that `value` may be zero.
               */
              event Transfer(address indexed from, address indexed to, uint256 value);
              /**
               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
               * a call to {approve}. `value` is the new allowance.
               */
              event Approval(
                  address indexed owner,
                  address indexed spender,
                  uint256 value
              );
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/math/Math.sol>
          // OpenZeppelin Contracts v4.4.0 (utils/math/Math.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Standard math utilities missing in the Solidity language.
           */
          library Math {
              /**
               * @dev Returns the largest of two numbers.
               */
              function max(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a >= b ? a : b;
              }
              /**
               * @dev Returns the smallest of two numbers.
               */
              function min(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a < b ? a : b;
              }
              /**
               * @dev Returns the average of two numbers. The result is rounded towards
               * zero.
               */
              function average(uint256 a, uint256 b) internal pure returns (uint256) {
                  // (a + b) / 2 can overflow.
                  return (a & b) + (a ^ b) / 2;
              }
              /**
               * @dev Returns the ceiling of the division of two numbers.
               *
               * This differs from standard division with `/` in that it rounds up instead
               * of rounding down.
               */
              function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                  // (a + b - 1) / b can overflow on addition, so we distribute.
                  return a / b + (a % b == 0 ? 0 : 1);
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          /// @dev The contract functions that are shared between the `Vesting` and
          /// `Claiming` contracts. The two components are handled and tested
          /// separately and are linked to each other by the functions in this contract.
          /// This contracs is for all intents and purposes an interface, however actual
          /// interfaces cannot declare internal functions.
          /// @title COW token vesting interface.
          /// @author CoW Protocol Developers
          abstract contract VestingInterface {
              /// @dev Adds an amount that will be vested over time.
              /// Should be called from the parent contract on redeeming a vested claim.
              /// @param user The user for whom the vesting is performed.
              /// @param vestingAmount The (added) amount to be vested in time.
              /// @param isCancelableFlag Flag whether the vesting is cancelable
              function addVesting(
                  address user,
                  uint256 vestingAmount,
                  bool isCancelableFlag
              ) internal virtual;
              /// @dev Computes the current vesting from the total vested amount and marks
              /// that amount as converted. This is called by the parent contract every
              /// time virtual tokens from a vested claim are swapped into real tokens.
              /// @param user The user for which the amount is vested.
              /// @return Amount converted.
              function vest(address user) internal virtual returns (uint256);
              /// @dev Transfers a cancelable vesting of a user to another address.
              /// Returns the amount of token that is not yet converted.
              /// @param user The user for whom the vesting is removed.
              /// @param freedVestingBeneficiary The address to which to assign the amount
              /// that remains to be vested.
              /// @return accruedVesting The total number of tokens that remain to be
              /// converted
              function shiftVesting(address user, address freedVestingBeneficiary)
                  internal
                  virtual
                  returns (uint256 accruedVesting);
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          // Vendored from GPv2 contracts v1.1.2, see:
          // <https://raw.githubusercontent.com/gnosis/gp-v2-contracts/7fb88982021e9a274d631ffb598694e6d9b30089/src/contracts/libraries/GPv2SafeERC20.sol>
          // The following changes were made:
          // - Bumped up Solidity version and checked that the assembly is still valid.
          // - Use own vendored IERC20 instead of custom implementation.
          // - Removed "GPv2" from contract name.
          // - Modified revert messages, including length.
          pragma solidity ^0.8.10;
          import "../interfaces/IERC20.sol";
          /// @title Gnosis Protocol v2 Safe ERC20 Transfer Library
          /// @author Gnosis Developers
          /// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract.
          library SafeERC20 {
              /// @dev Wrapper around a call to the ERC20 function `transfer` that reverts
              /// also when the token returns `false`.
              function safeTransfer(
                  IERC20 token,
                  address to,
                  uint256 value
              ) internal {
                  bytes4 selector_ = token.transfer.selector;
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      let freeMemoryPointer := mload(0x40)
                      mstore(freeMemoryPointer, selector_)
                      mstore(
                          add(freeMemoryPointer, 4),
                          and(to, 0xffffffffffffffffffffffffffffffffffffffff)
                      )
                      mstore(add(freeMemoryPointer, 36), value)
                      if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) {
                          returndatacopy(0, 0, returndatasize())
                          revert(0, returndatasize())
                      }
                  }
                  require(getLastTransferResult(token), "SafeERC20: failed transfer");
              }
              /// @dev Wrapper around a call to the ERC20 function `transferFrom` that
              /// reverts also when the token returns `false`.
              function safeTransferFrom(
                  IERC20 token,
                  address from,
                  address to,
                  uint256 value
              ) internal {
                  bytes4 selector_ = token.transferFrom.selector;
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      let freeMemoryPointer := mload(0x40)
                      mstore(freeMemoryPointer, selector_)
                      mstore(
                          add(freeMemoryPointer, 4),
                          and(from, 0xffffffffffffffffffffffffffffffffffffffff)
                      )
                      mstore(
                          add(freeMemoryPointer, 36),
                          and(to, 0xffffffffffffffffffffffffffffffffffffffff)
                      )
                      mstore(add(freeMemoryPointer, 68), value)
                      if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) {
                          returndatacopy(0, 0, returndatasize())
                          revert(0, returndatasize())
                      }
                  }
                  require(getLastTransferResult(token), "SafeERC20: failed transferFrom");
              }
              /// @dev Verifies that the last return was a successful `transfer*` call.
              /// This is done by checking that the return data is either empty, or
              /// is a valid ABI encoded boolean.
              function getLastTransferResult(IERC20 token)
                  private
                  view
                  returns (bool success)
              {
                  // NOTE: Inspecting previous return data requires assembly. Note that
                  // we write the return data to memory 0 in the case where the return
                  // data size is 32, this is OK since the first 64 bytes of memory are
                  // reserved by Solidy as a scratch space that can be used within
                  // assembly blocks.
                  // <https://docs.soliditylang.org/en/v0.8.10/internals/layout_in_memory.html>
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      /// @dev Revert with an ABI encoded Solidity error with a message
                      /// that fits into 32-bytes.
                      ///
                      /// An ABI encoded Solidity error has the following memory layout:
                      ///
                      /// ------------+----------------------------------
                      ///  byte range | value
                      /// ------------+----------------------------------
                      ///  0x00..0x04 |        selector("Error(string)")
                      ///  0x04..0x24 |      string offset (always 0x20)
                      ///  0x24..0x44 |                    string length
                      ///  0x44..0x64 | string value, padded to 32-bytes
                      function revertWithMessage(length, message) {
                          mstore(0x00, "\\x08\\xc3\\x79\\xa0")
                          mstore(0x04, 0x20)
                          mstore(0x24, length)
                          mstore(0x44, message)
                          revert(0x00, 0x64)
                      }
                      switch returndatasize()
                      // Non-standard ERC20 transfer without return.
                      case 0 {
                          // NOTE: When the return data size is 0, verify that there
                          // is code at the address. This is done in order to maintain
                          // compatibility with Solidity calling conventions.
                          // <https://docs.soliditylang.org/en/v0.8.10/control-structures.html#external-function-calls>
                          if iszero(extcodesize(token)) {
                              revertWithMessage(25, "SafeERC20: not a contract")
                          }
                          success := 1
                      }
                      // Standard ERC20 transfer returning boolean success value.
                      case 32 {
                          returndatacopy(0, 0, returndatasize())
                          // NOTE: For ABI encoding v1, any non-zero value is accepted
                          // as `true` for a boolean. In order to stay compatible with
                          // OpenZeppelin's `SafeERC20` library which is known to work
                          // with the existing ERC20 implementation we care about,
                          // make sure we return success for any non-zero return value
                          // from the `transfer*` call.
                          success := iszero(iszero(mload(0)))
                      }
                      default {
                          revertWithMessage(30, "SafeERC20: bad transfer result")
                      }
                  }
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          /// @dev The contract functions that are shared between the `Claiming` and
          /// `MerkleDistributor` contracts. The two components are handled and tested
          /// separately and are linked to each other by the functions in this contract.
          /// This contracs is for all intents and purposes an interface, however actual
          /// interfaces cannot declare internal functions.
          /// @title COW token claiming interface.
          /// @author CoW Protocol Developers
          abstract contract ClaimingInterface {
              /// @dev Exhaustive list of the different branches of the claiming logic.
              enum ClaimType {
                  Airdrop,
                  GnoOption,
                  UserOption,
                  Investor,
                  Team,
                  Advisor
              }
              /// @dev This function is executed when a valid proof of the claim is
              /// provided and executes all steps required for each claim type.
              /// @param claimType Which claim will be performed. See [`ClaimType`] for
              /// an exausting list.
              /// @param payer The address that will pay if the claim to be performed
              /// requires a payment.
              /// @param claimant The account to which the claim is assigned and which
              /// will receive the corresponding virtual tokens.
              /// @param claimedAmount The amount that the user decided to claim (after
              /// vesting if it applies).
              /// @param sentNativeTokens The amount of native tokens that the user sent
              /// along with the transaction.
              function performClaim(
                  ClaimType claimType,
                  address payer,
                  address claimant,
                  uint256 claimedAmount,
                  uint256 sentNativeTokens
              ) internal virtual;
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/cryptography/MerkleProof.sol>
          // OpenZeppelin Contracts v4.4.0 (utils/cryptography/MerkleProof.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev These functions deal with verification of Merkle Trees proofs.
           *
           * The proofs can be generated using the JavaScript library
           * https://github.com/miguelmota/merkletreejs[merkletreejs].
           * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
           *
           * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
           */
          library MerkleProof {
              /**
               * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
               * defined by `root`. For this, a `proof` must be provided, containing
               * sibling hashes on the branch from the leaf to the root of the tree. Each
               * pair of leaves and each pair of pre-images are assumed to be sorted.
               */
              function verify(
                  bytes32[] memory proof,
                  bytes32 root,
                  bytes32 leaf
              ) internal pure returns (bool) {
                  return processProof(proof, leaf) == root;
              }
              /**
               * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up
               * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
               * hash matches the root of the tree. When processing the proof, the pairs
               * of leafs & pre-images are assumed to be sorted.
               *
               * _Available since v4.4._
               */
              function processProof(bytes32[] memory proof, bytes32 leaf)
                  internal
                  pure
                  returns (bytes32)
              {
                  bytes32 computedHash = leaf;
                  for (uint256 i = 0; i < proof.length; i++) {
                      bytes32 proofElement = proof[i];
                      if (computedHash <= proofElement) {
                          // Hash(current computed hash + current element of the proof)
                          computedHash = keccak256(
                              abi.encodePacked(computedHash, proofElement)
                          );
                      } else {
                          // Hash(current element of the proof + current computed hash)
                          computedHash = keccak256(
                              abi.encodePacked(proofElement, computedHash)
                          );
                      }
                  }
                  return computedHash;
              }
          }
          

          File 2 of 2: CowProtocolToken
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "./mixins/InflationaryToken.sol";
          import "./vendored/mixins/StorageAccessible.sol";
          /// @dev The governance token for the CoW Protocol.
          /// @title CoW Protocol Governance Token
          /// @author CoW Protocol Developers
          contract CowProtocolToken is InflationaryToken, StorageAccessible {
              string private constant ERC20_SYMBOL = "COW";
              string private constant ERC20_NAME = "CoW Protocol Token";
              constructor(
                  address initialTokenHolder,
                  address cowDao,
                  uint256 totalSupply
              )
                  InflationaryToken(
                      initialTokenHolder,
                      cowDao,
                      totalSupply,
                      ERC20_NAME,
                      ERC20_SYMBOL
                  )
              // solhint-disable-next-line no-empty-blocks
              {
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-or-later
          pragma solidity ^0.8.10;
          import "../vendored/mixins/ERC20.sol";
          import "../vendored/mixins/draft-ERC20Permit.sol";
          /// @dev Contract contains the logic for minting new tokens
          /// @title Mintable Token
          /// @author CoW Protocol Developers
          contract InflationaryToken is ERC20, ERC20Permit {
              /// @dev Defines the cowDao address that is allowed to mint new tokens
              address public immutable cowDao;
              /// @dev Defines how frequently inflation can be triggered: Once a year
              uint256 public constant TIME_BETWEEN_MINTINGS = 365 days;
              /// @dev Defines the maximal inflation per year
              uint256 public constant MAX_YEARLY_INFLATION = 3;
              /// @dev Stores the timestamp of the last inflation event
              uint256 public timestampLastMinting = 0;
              /// @dev Error caused by an attempt to mint too many tokens.
              error ExceedingMintCap();
              /// @dev Error caused by calling the mint function more than once within one year.
              error AlreadyInflated();
              /// @dev Error caused by calling the mint function from a non-cowDao account.
              error OnlyCowDao();
              modifier onlyCowDao() {
                  if (msg.sender != cowDao) {
                      revert OnlyCowDao();
                  }
                  _;
              }
              constructor(
                  address initialTokenHolder,
                  address _cowDao,
                  uint256 totalSupply,
                  string memory erc20Name,
                  string memory erc20Symbol
              ) ERC20(erc20Name, erc20Symbol) ERC20Permit(erc20Name) {
                  _mint(initialTokenHolder, totalSupply);
                  cowDao = _cowDao;
                  // solhint-disable-next-line not-rely-on-time
                  timestampLastMinting = block.timestamp;
              }
              /// @dev This function allows to mint new tokens
              /// @param target The address that should receive the new tokens
              /// @param amount The amount of tokens to be minted.
              function mint(address target, uint256 amount) external onlyCowDao {
                  if (amount > (totalSupply() * MAX_YEARLY_INFLATION) / 100) {
                      revert ExceedingMintCap();
                  }
                  // solhint-disable-next-line not-rely-on-time
                  if (timestampLastMinting + TIME_BETWEEN_MINTINGS > block.timestamp) {
                      revert AlreadyInflated();
                  }
                  timestampLastMinting = block.timestamp; // solhint-disable-line not-rely-on-time
                  _mint(target, amount);
              }
          }
          // SPDX-License-Identifier: LGPL-3.0-only
          // Vendored from Gnosis utility contracts, see:
          // <https://raw.githubusercontent.com/gnosis/gp-v2-contracts/40c349d52d14f8f3c9f787fe2fca5a496bb10ea9/src/contracts/mixins/StorageAccessible.sol>
          // The following changes were made:
          // - Modified Solidity version
          // - Formatted code
          pragma solidity ^0.8.10;
          /// @title ViewStorageAccessible - Interface on top of StorageAccessible base class to allow simulations from view functions
          interface ViewStorageAccessible {
              /**
               * @dev Same as `simulateDelegatecall` on StorageAccessible. Marked as view so that it can be called from external contracts
               * that want to run simulations from within view functions. Will revert if the invoked simulation attempts to change state.
               */
              function simulateDelegatecall(
                  address targetContract,
                  bytes memory calldataPayload
              ) external view returns (bytes memory);
              /**
               * @dev Same as `getStorageAt` on StorageAccessible. This method allows reading aribtrary ranges of storage.
               */
              function getStorageAt(uint256 offset, uint256 length)
                  external
                  view
                  returns (bytes memory);
          }
          /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
          contract StorageAccessible {
              /**
               * @dev Reads `length` bytes of storage in the currents contract
               * @param offset - the offset in the current contract's storage in words to start reading from
               * @param length - the number of words (32 bytes) of data to read
               * @return the bytes that were read.
               */
              function getStorageAt(uint256 offset, uint256 length)
                  external
                  view
                  returns (bytes memory)
              {
                  bytes memory result = new bytes(length * 32);
                  for (uint256 index = 0; index < length; index++) {
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          let word := sload(add(offset, index))
                          mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                      }
                  }
                  return result;
              }
              /**
               * @dev Performs a delegetecall on a targetContract in the context of self.
               * Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result as bytes.
               * @param targetContract Address of the contract containing the code to execute.
               * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
               */
              function simulateDelegatecall(
                  address targetContract,
                  bytes memory calldataPayload
              ) public returns (bytes memory response) {
                  bytes memory innerCall = abi.encodeWithSelector(
                      this.simulateDelegatecallInternal.selector,
                      targetContract,
                      calldataPayload
                  );
                  // solhint-disable-next-line avoid-low-level-calls
                  (, response) = address(this).call(innerCall);
                  bool innerSuccess = response[response.length - 1] == 0x01;
                  setLength(response, response.length - 1);
                  if (innerSuccess) {
                      return response;
                  } else {
                      revertWith(response);
                  }
              }
              /**
               * @dev Performs a delegetecall on a targetContract in the context of self.
               * Internally reverts execution to avoid side effects (making it static). Returns encoded result as revert message
               * concatenated with the success flag of the inner call as a last byte.
               * @param targetContract Address of the contract containing the code to execute.
               * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
               */
              function simulateDelegatecallInternal(
                  address targetContract,
                  bytes memory calldataPayload
              ) external returns (bytes memory response) {
                  bool success;
                  // solhint-disable-next-line avoid-low-level-calls
                  (success, response) = targetContract.delegatecall(calldataPayload);
                  revertWith(abi.encodePacked(response, success));
              }
              function revertWith(bytes memory response) internal pure {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      revert(add(response, 0x20), mload(response))
                  }
              }
              function setLength(bytes memory buffer, uint256 length) internal pure {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      mstore(buffer, length)
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/ERC20.sol>
          // The following changes were made:
          // - Vendored imports
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/ERC20.sol)
          pragma solidity ^0.8.0;
          import "../interfaces/IERC20.sol";
          import "../interfaces/IERC20Metadata.sol";
          import "../interfaces/Context.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 Contracts guidelines: functions revert
           * instead 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, IERC20Metadata {
              mapping(address => uint256) private _balances;
              mapping(address => mapping(address => uint256)) private _allowances;
              uint256 private _totalSupply;
              string private _name;
              string private _symbol;
              /**
               * @dev Sets the values for {name} and {symbol}.
               *
               * The default value of {decimals} is 18. To select a different value for
               * {decimals} you should overload it.
               *
               * All two of these values are immutable: they can only be set once during
               * construction.
               */
              constructor(string memory name_, string memory symbol_) {
                  _name = name_;
                  _symbol = symbol_;
              }
              /**
               * @dev Returns the name of the token.
               */
              function name() public view virtual override returns (string memory) {
                  return _name;
              }
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view virtual override returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5.05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei. This is the value {ERC20} uses, unless this function is
               * overridden;
               *
               * 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 override returns (uint8) {
                  return 18;
              }
              /**
               * @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);
                  uint256 currentAllowance = _allowances[sender][_msgSender()];
                  require(
                      currentAllowance >= amount,
                      "ERC20: transfer amount exceeds allowance"
                  );
                  unchecked {
                      _approve(sender, _msgSender(), currentAllowance - amount);
                  }
                  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] + 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)
              {
                  uint256 currentAllowance = _allowances[_msgSender()][spender];
                  require(
                      currentAllowance >= subtractedValue,
                      "ERC20: decreased allowance below zero"
                  );
                  unchecked {
                      _approve(_msgSender(), spender, currentAllowance - subtractedValue);
                  }
                  return true;
              }
              /**
               * @dev Moves `amount` of tokens from `sender` to `recipient`.
               *
               * This 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);
                  uint256 senderBalance = _balances[sender];
                  require(
                      senderBalance >= amount,
                      "ERC20: transfer amount exceeds balance"
                  );
                  unchecked {
                      _balances[sender] = senderBalance - amount;
                  }
                  _balances[recipient] += amount;
                  emit Transfer(sender, recipient, amount);
                  _afterTokenTransfer(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:
               *
               * - `account` 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 += amount;
                  _balances[account] += amount;
                  emit Transfer(address(0), account, amount);
                  _afterTokenTransfer(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);
                  uint256 accountBalance = _balances[account];
                  require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
                  unchecked {
                      _balances[account] = accountBalance - amount;
                  }
                  _totalSupply -= amount;
                  emit Transfer(account, address(0), amount);
                  _afterTokenTransfer(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 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 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 {}
              /**
               * @dev Hook that is called after any transfer of tokens. This includes
               * minting and burning.
               *
               * Calling conditions:
               *
               * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
               * has been transferred to `to`.
               * - when `from` is zero, `amount` tokens have been minted for `to`.
               * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
                  address from,
                  address to,
                  uint256 amount
              ) internal virtual {}
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/extensions/draft-ERC20Permit.sol>
          // The following changes were made:
          // - Vendored imports
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/draft-ERC20Permit.sol)
          pragma solidity ^0.8.0;
          import "../interfaces/draft-IERC20Permit.sol";
          import "./ERC20.sol";
          import "./draft-EIP712.sol";
          import "../libraries/ECDSA.sol";
          import "../libraries/Counters.sol";
          /**
           * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
           *
           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
           * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
           * need to send a transaction, and thus is not required to hold Ether at all.
           *
           * _Available since v3.4._
           */
          abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
              using Counters for Counters.Counter;
              mapping(address => Counters.Counter) private _nonces;
              // solhint-disable-next-line var-name-mixedcase
              bytes32 private immutable _PERMIT_TYPEHASH =
                  keccak256(
                      "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                  );
              /**
               * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
               *
               * It's a good idea to use the same `name` that is defined as the ERC20 token name.
               */
              constructor(string memory name) EIP712(name, "1") {}
              /**
               * @dev See {IERC20Permit-permit}.
               */
              function permit(
                  address owner,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) public virtual override {
                  require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
                  bytes32 structHash = keccak256(
                      abi.encode(
                          _PERMIT_TYPEHASH,
                          owner,
                          spender,
                          value,
                          _useNonce(owner),
                          deadline
                      )
                  );
                  bytes32 hash = _hashTypedDataV4(structHash);
                  address signer = ECDSA.recover(hash, v, r, s);
                  require(signer == owner, "ERC20Permit: invalid signature");
                  _approve(owner, spender, value);
              }
              /**
               * @dev See {IERC20Permit-nonces}.
               */
              function nonces(address owner)
                  public
                  view
                  virtual
                  override
                  returns (uint256)
              {
                  return _nonces[owner].current();
              }
              /**
               * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
               */
              // solhint-disable-next-line func-name-mixedcase
              function DOMAIN_SEPARATOR() external view override returns (bytes32) {
                  return _domainSeparatorV4();
              }
              /**
               * @dev "Consume a nonce": return the current value and increment.
               *
               * _Available since v4.1._
               */
              function _useNonce(address owner)
                  internal
                  virtual
                  returns (uint256 current)
              {
                  Counters.Counter storage nonce = _nonces[owner];
                  current = nonce.current();
                  nonce.increment();
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/IERC20.sol>
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC20 standard as defined in the EIP.
           */
          interface IERC20 {
              /**
               * @dev Returns the amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `recipient`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address recipient, uint256 amount)
                  external
                  returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender)
                  external
                  view
                  returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `sender` to `recipient` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address sender,
                  address recipient,
                  uint256 amount
              ) external returns (bool);
              /**
               * @dev Emitted when `value` tokens are moved from one account (`from`) to
               * another (`to`).
               *
               * Note that `value` may be zero.
               */
              event Transfer(address indexed from, address indexed to, uint256 value);
              /**
               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
               * a call to {approve}. `value` is the new allowance.
               */
              event Approval(
                  address indexed owner,
                  address indexed spender,
                  uint256 value
              );
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/extensions/IERC20Metadata.sol>
          // The following changes were made:
          // - Vendored imports
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/IERC20Metadata.sol)
          pragma solidity ^0.8.0;
          import "./IERC20.sol";
          /**
           * @dev Interface for the optional metadata functions from the ERC20 standard.
           *
           * _Available since v4.1._
           */
          interface IERC20Metadata is IERC20 {
              /**
               * @dev Returns the name of the token.
               */
              function name() external view returns (string memory);
              /**
               * @dev Returns the symbol of the token.
               */
              function symbol() external view returns (string memory);
              /**
               * @dev Returns the decimals places of the token.
               */
              function decimals() external view returns (uint8);
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/Context.sol>
          // OpenZeppelin Contracts v4.4.0 (utils/Context.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/token/ERC20/extensions/draft-IERC20Permit.sol>
          // OpenZeppelin Contracts v4.4.0 (token/ERC20/extensions/draft-IERC20Permit.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
           *
           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
           * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
           * need to send a transaction, and thus is not required to hold Ether at all.
           */
          interface IERC20Permit {
              /**
               * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
               * given ``owner``'s signed approval.
               *
               * IMPORTANT: The same issues {IERC20-approve} has related to transaction
               * ordering also apply here.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `deadline` must be a timestamp in the future.
               * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
               * over the EIP712-formatted function arguments.
               * - the signature must use ``owner``'s current nonce (see {nonces}).
               *
               * For more information on the signature format, see the
               * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
               * section].
               */
              function permit(
                  address owner,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) external;
              /**
               * @dev Returns the current nonce for `owner`. This value must be
               * included whenever a signature is generated for {permit}.
               *
               * Every successful call to {permit} increases ``owner``'s nonce by one. This
               * prevents a signature from being used multiple times.
               */
              function nonces(address owner) external view returns (uint256);
              /**
               * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
               */
              // solhint-disable-next-line func-name-mixedcase
              function DOMAIN_SEPARATOR() external view returns (bytes32);
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/cryptography/draft-EIP712.sol>
          // The following changes were made:
          // - Vendored imports
          // OpenZeppelin Contracts v4.4.0 (utils/cryptography/draft-EIP712.sol)
          pragma solidity ^0.8.0;
          import "../libraries/ECDSA.sol";
          /**
           * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
           *
           * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
           * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
           * they need in their contracts using a combination of `abi.encode` and `keccak256`.
           *
           * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
           * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
           * ({_hashTypedDataV4}).
           *
           * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
           * the chain id to protect against replay attacks on an eventual fork of the chain.
           *
           * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
           * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
           *
           * _Available since v3.4._
           */
          abstract contract EIP712 {
              /* solhint-disable var-name-mixedcase */
              // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
              // invalidate the cached domain separator if the chain id changes.
              bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
              uint256 private immutable _CACHED_CHAIN_ID;
              address private immutable _CACHED_THIS;
              bytes32 private immutable _HASHED_NAME;
              bytes32 private immutable _HASHED_VERSION;
              bytes32 private immutable _TYPE_HASH;
              /* solhint-enable var-name-mixedcase */
              /**
               * @dev Initializes the domain separator and parameter caches.
               *
               * The meaning of `name` and `version` is specified in
               * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
               *
               * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
               * - `version`: the current major version of the signing domain.
               *
               * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
               * contract upgrade].
               */
              constructor(string memory name, string memory version) {
                  bytes32 hashedName = keccak256(bytes(name));
                  bytes32 hashedVersion = keccak256(bytes(version));
                  bytes32 typeHash = keccak256(
                      "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                  );
                  _HASHED_NAME = hashedName;
                  _HASHED_VERSION = hashedVersion;
                  _CACHED_CHAIN_ID = block.chainid;
                  _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(
                      typeHash,
                      hashedName,
                      hashedVersion
                  );
                  _CACHED_THIS = address(this);
                  _TYPE_HASH = typeHash;
              }
              /**
               * @dev Returns the domain separator for the current chain.
               */
              function _domainSeparatorV4() internal view returns (bytes32) {
                  if (
                      address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID
                  ) {
                      return _CACHED_DOMAIN_SEPARATOR;
                  } else {
                      return
                          _buildDomainSeparator(
                              _TYPE_HASH,
                              _HASHED_NAME,
                              _HASHED_VERSION
                          );
                  }
              }
              function _buildDomainSeparator(
                  bytes32 typeHash,
                  bytes32 nameHash,
                  bytes32 versionHash
              ) private view returns (bytes32) {
                  return
                      keccak256(
                          abi.encode(
                              typeHash,
                              nameHash,
                              versionHash,
                              block.chainid,
                              address(this)
                          )
                      );
              }
              /**
               * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
               * function returns the hash of the fully encoded EIP712 message for this domain.
               *
               * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
               *
               * ```solidity
               * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
               *     keccak256("Mail(address to,string contents)"),
               *     mailTo,
               *     keccak256(bytes(mailContents))
               * )));
               * address signer = ECDSA.recover(digest, signature);
               * ```
               */
              function _hashTypedDataV4(bytes32 structHash)
                  internal
                  view
                  virtual
                  returns (bytes32)
              {
                  return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/cryptography/ECDSA.sol>
          // The following changes were made:
          // - Vendored imports
          // OpenZeppelin Contracts v4.4.0 (utils/cryptography/ECDSA.sol)
          pragma solidity ^0.8.0;
          import "./Strings.sol";
          /**
           * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
           *
           * These functions can be used to verify that a message was signed by the holder
           * of the private keys of a given address.
           */
          library ECDSA {
              enum RecoverError {
                  NoError,
                  InvalidSignature,
                  InvalidSignatureLength,
                  InvalidSignatureS,
                  InvalidSignatureV
              }
              function _throwError(RecoverError error) private pure {
                  if (error == RecoverError.NoError) {
                      return; // no error: do nothing
                  } else if (error == RecoverError.InvalidSignature) {
                      revert("ECDSA: invalid signature");
                  } else if (error == RecoverError.InvalidSignatureLength) {
                      revert("ECDSA: invalid signature length");
                  } else if (error == RecoverError.InvalidSignatureS) {
                      revert("ECDSA: invalid signature 's' value");
                  } else if (error == RecoverError.InvalidSignatureV) {
                      revert("ECDSA: invalid signature 'v' value");
                  }
              }
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with
               * `signature` or error string. This address can then be used for verification purposes.
               *
               * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {toEthSignedMessageHash} on it.
               *
               * Documentation for signature generation:
               * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
               * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
               *
               * _Available since v4.3._
               */
              function tryRecover(bytes32 hash, bytes memory signature)
                  internal
                  pure
                  returns (address, RecoverError)
              {
                  // Check the signature length
                  // - case 65: r,s,v signature (standard)
                  // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
                  if (signature.length == 65) {
                      bytes32 r;
                      bytes32 s;
                      uint8 v;
                      // ecrecover takes the signature parameters, and the only way to get them
                      // currently is to use assembly.
                      assembly {
                          r := mload(add(signature, 0x20))
                          s := mload(add(signature, 0x40))
                          v := byte(0, mload(add(signature, 0x60)))
                      }
                      return tryRecover(hash, v, r, s);
                  } else if (signature.length == 64) {
                      bytes32 r;
                      bytes32 vs;
                      // ecrecover takes the signature parameters, and the only way to get them
                      // currently is to use assembly.
                      assembly {
                          r := mload(add(signature, 0x20))
                          vs := mload(add(signature, 0x40))
                      }
                      return tryRecover(hash, r, vs);
                  } else {
                      return (address(0), RecoverError.InvalidSignatureLength);
                  }
              }
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with
               * `signature`. This address can then be used for verification purposes.
               *
               * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {toEthSignedMessageHash} on it.
               */
              function recover(bytes32 hash, bytes memory signature)
                  internal
                  pure
                  returns (address)
              {
                  (address recovered, RecoverError error) = tryRecover(hash, signature);
                  _throwError(error);
                  return recovered;
              }
              /**
               * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
               *
               * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
               *
               * _Available since v4.3._
               */
              function tryRecover(
                  bytes32 hash,
                  bytes32 r,
                  bytes32 vs
              ) internal pure returns (address, RecoverError) {
                  bytes32 s;
                  uint8 v;
                  assembly {
                      s := and(
                          vs,
                          0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
                      )
                      v := add(shr(255, vs), 27)
                  }
                  return tryRecover(hash, v, r, s);
              }
              /**
               * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
               *
               * _Available since v4.2._
               */
              function recover(
                  bytes32 hash,
                  bytes32 r,
                  bytes32 vs
              ) internal pure returns (address) {
                  (address recovered, RecoverError error) = tryRecover(hash, r, vs);
                  _throwError(error);
                  return recovered;
              }
              /**
               * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
               * `r` and `s` signature fields separately.
               *
               * _Available since v4.3._
               */
              function tryRecover(
                  bytes32 hash,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) internal pure returns (address, RecoverError) {
                  // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                  // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                  // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                  // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                  //
                  // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                  // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                  // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                  // these malleable signatures as well.
                  if (
                      uint256(s) >
                      0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
                  ) {
                      return (address(0), RecoverError.InvalidSignatureS);
                  }
                  if (v != 27 && v != 28) {
                      return (address(0), RecoverError.InvalidSignatureV);
                  }
                  // If the signature is valid (and not malleable), return the signer address
                  address signer = ecrecover(hash, v, r, s);
                  if (signer == address(0)) {
                      return (address(0), RecoverError.InvalidSignature);
                  }
                  return (signer, RecoverError.NoError);
              }
              /**
               * @dev Overload of {ECDSA-recover} that receives the `v`,
               * `r` and `s` signature fields separately.
               */
              function recover(
                  bytes32 hash,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) internal pure returns (address) {
                  (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
                  _throwError(error);
                  return recovered;
              }
              /**
               * @dev Returns an Ethereum Signed Message, created from a `hash`. This
               * produces hash corresponding to the one signed with the
               * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
               * JSON-RPC method as part of EIP-191.
               *
               * See {recover}.
               */
              function toEthSignedMessageHash(bytes32 hash)
                  internal
                  pure
                  returns (bytes32)
              {
                  // 32 is the length in bytes of hash,
                  // enforced by the type signature above
                  return
                      keccak256(
                          abi.encodePacked("\\x19Ethereum Signed Message:\
          32", hash)
                      );
              }
              /**
               * @dev Returns an Ethereum Signed Message, created from `s`. This
               * produces hash corresponding to the one signed with the
               * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
               * JSON-RPC method as part of EIP-191.
               *
               * See {recover}.
               */
              function toEthSignedMessageHash(bytes memory s)
                  internal
                  pure
                  returns (bytes32)
              {
                  return
                      keccak256(
                          abi.encodePacked(
                              "\\x19Ethereum Signed Message:\
          ",
                              Strings.toString(s.length),
                              s
                          )
                      );
              }
              /**
               * @dev Returns an Ethereum Signed Typed Data, created from a
               * `domainSeparator` and a `structHash`. This produces hash corresponding
               * to the one signed with the
               * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
               * JSON-RPC method as part of EIP-712.
               *
               * See {recover}.
               */
              function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash)
                  internal
                  pure
                  returns (bytes32)
              {
                  return
                      keccak256(
                          abi.encodePacked("\\x19\\x01", domainSeparator, structHash)
                      );
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/Counters.sol>
          // OpenZeppelin Contracts v4.4.0 (utils/Counters.sol)
          pragma solidity ^0.8.0;
          /**
           * @title Counters
           * @author Matt Condon (@shrugs)
           * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
           * of elements in a mapping, issuing ERC721 ids, or counting request ids.
           *
           * Include with `using Counters for Counters.Counter;`
           */
          library Counters {
              struct Counter {
                  // This variable should never be directly accessed by users of the library: interactions must be restricted to
                  // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
                  // this feature: see https://github.com/ethereum/solidity/issues/4637
                  uint256 _value; // default: 0
              }
              function current(Counter storage counter) internal view returns (uint256) {
                  return counter._value;
              }
              function increment(Counter storage counter) internal {
                  unchecked {
                      counter._value += 1;
                  }
              }
              function decrement(Counter storage counter) internal {
                  uint256 value = counter._value;
                  require(value > 0, "Counter: decrement overflow");
                  unchecked {
                      counter._value = value - 1;
                  }
              }
              function reset(Counter storage counter) internal {
                  counter._value = 0;
              }
          }
          // SPDX-License-Identifier: MIT
          // Vendored from OpenZeppelin Contracts v4.4.0, see:
          // <https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/v4.4.0/contracts/utils/Strings.sol>
          // OpenZeppelin Contracts v4.4.0 (utils/Strings.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev String operations.
           */
          library Strings {
              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
              /**
               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  while (value != 0) {
                      digits -= 1;
                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                      value /= 10;
                  }
                  return string(buffer);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
               */
              function toHexString(uint256 value) internal pure returns (string memory) {
                  if (value == 0) {
                      return "0x00";
                  }
                  uint256 temp = value;
                  uint256 length = 0;
                  while (temp != 0) {
                      length++;
                      temp >>= 8;
                  }
                  return toHexString(value, length);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
               */
              function toHexString(uint256 value, uint256 length)
                  internal
                  pure
                  returns (string memory)
              {
                  bytes memory buffer = new bytes(2 * length + 2);
                  buffer[0] = "0";
                  buffer[1] = "x";
                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                      value >>= 4;
                  }
                  require(value == 0, "Strings: hex length insufficient");
                  return string(buffer);
              }
          }