ETH Price: $1,877.50 (+0.43%)

Transaction Decoder

Block:
22032603 at Mar-12-2025 06:33:11 PM +UTC
Transaction Fee:
0.000052259475681556 ETH $0.10
Gas Used:
86,801 Gas / 0.602060756 Gwei

Emitted Events:

306 KIP.Transfer( from=UprisingAirdropDistributorAfterInit, to=[Sender] 0x6b10c72bc2b6d23ee987f8ffa0a512246f014a6f, value=910000000000000000000 )
307 UprisingAirdropDistributorAfterInit.Claimed( caller=[Sender] 0x6b10c72bc2b6d23ee987f8ffa0a512246f014a6f, userVestingId=0000000000000000000000006B10C72BC2B6D23EE987F8FFA0A512246F014A6F, recipient=[Sender] 0x6b10c72bc2b6d23ee987f8ffa0a512246f014a6f, amount=910000000000000000000 )
308 BatchDistributor.BatchClaimed( caller=[Sender] 0x6b10c72bc2b6d23ee987f8ffa0a512246f014a6f, distributors=[0x014E49891531Ef2C30545Fc726B17903db8FbFbc], recipient=[Sender] 0x6b10c72bc2b6d23ee987f8ffa0a512246f014a6f )

Account State Difference:

  Address   Before After State Difference Code
0x014E4989...3db8FbFbc
3.135058554955348824 Eth3.135059101084585763 Eth0.000000546129236939
0x6b10C72b...46f014A6f
0.000496707164376061 Eth
Nonce: 6
0.000444447688694505 Eth
Nonce: 7
0.000052259475681556
0x946fb081...fd26cd374

Execution Trace

BatchDistributor.batchClaim( params=, recipient=0x6b10C72bC2b6D23Ee987F8ffA0a512246f014A6f )
  • UprisingAirdropDistributorAfterInit.claim( caller=0x6b10C72bC2b6D23Ee987F8ffA0a512246f014A6f, userVestingId=0000000000000000000000006B10C72BC2B6D23EE987F8FFA0A512246F014A6F, recipient=0x6b10C72bC2b6D23Ee987F8ffA0a512246f014A6f )
    • UprisingAirdropDistributorAfterInit.slotInfos( userVestingId=0000000000000000000000006B10C72BC2B6D23EE987F8FFA0A512246F014A6F ) => ( [{name:amount, type:uint256, order:1, indexed:false, value:6500000000000000000000, valueString:6500000000000000000000}, {name:claimed, type:uint256, order:2, indexed:false, value:3770000000000000000000, valueString:3770000000000000000000}, {name:initDeadline, type:uint128, order:3, indexed:false, value:1736474700, valueString:1736474700}, {name:startTime, type:uint128, order:4, indexed:false, value:1733900675, valueString:1733900675}, {name:initClaimPercent, type:uint32, order:5, indexed:false, value:3000, valueString:3000}, {name:intervalPercent, type:uint32, order:6, indexed:false, value:1400, valueString:1400}, {name:intervalDays, type:uint32, order:7, indexed:false, value:30, valueString:30}, {name:initialized, type:bool, order:8, indexed:false, value:true, valueString:True}] )
    • KIP.transfer( to=0x6b10C72bC2b6D23Ee987F8ffA0a512246f014A6f, value=910000000000000000000 ) => ( True )
      File 1 of 3: BatchDistributor
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Contract module that helps prevent reentrant calls to a function.
       *
       * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
       * available, which can be applied to functions to make sure there are no nested
       * (reentrant) calls to them.
       *
       * Note that because there is a single `nonReentrant` guard, functions marked as
       * `nonReentrant` may not call one another. This can be worked around by making
       * those functions `private`, and then adding `external` `nonReentrant` entry
       * points to them.
       *
       * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
       * consider using {ReentrancyGuardTransient} instead.
       *
       * TIP: If you would like to learn more about reentrancy and alternative ways
       * to protect against it, check out our blog post
       * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
       */
      abstract contract ReentrancyGuard {
          // Booleans are more expensive than uint256 or any type that takes up a full
          // word because each write operation emits an extra SLOAD to first read the
          // slot's contents, replace the bits taken up by the boolean, and then write
          // back. This is the compiler's defense against contract upgrades and
          // pointer aliasing, and it cannot be disabled.
          // The values being non-zero value makes deployment a bit more expensive,
          // but in exchange the refund on every call to nonReentrant will be lower in
          // amount. Since refunds are capped to a percentage of the total
          // transaction's gas, it is best to keep them low in cases like this one, to
          // increase the likelihood of the full refund coming into effect.
          uint256 private constant NOT_ENTERED = 1;
          uint256 private constant ENTERED = 2;
          uint256 private _status;
          /**
           * @dev Unauthorized reentrant call.
           */
          error ReentrancyGuardReentrantCall();
          constructor() {
              _status = NOT_ENTERED;
          }
          /**
           * @dev Prevents a contract from calling itself, directly or indirectly.
           * Calling a `nonReentrant` function from another `nonReentrant`
           * function is not supported. It is possible to prevent this from happening
           * by making the `nonReentrant` function external, and making it call a
           * `private` function that does the actual work.
           */
          modifier nonReentrant() {
              _nonReentrantBefore();
              _;
              _nonReentrantAfter();
          }
          function _nonReentrantBefore() private {
              // On the first call to nonReentrant, _status will be NOT_ENTERED
              if (_status == ENTERED) {
                  revert ReentrancyGuardReentrantCall();
              }
              // Any calls to nonReentrant after this point will fail
              _status = ENTERED;
          }
          function _nonReentrantAfter() private {
              // By storing the original value once again, a refund is triggered (see
              // https://eips.ethereum.org/EIPS/eip-2200)
              _status = NOT_ENTERED;
          }
          /**
           * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
           * `nonReentrant` function in the call stack.
           */
          function _reentrancyGuardEntered() internal view returns (bool) {
              return _status == ENTERED;
          }
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      error InvalidSignature();
      error AlreadyClaimed();
      error ZeroAddress();
      error DeadlinePassed();
      error InvalidProofs();
      error RootHashAlreadySet();
      error SlotExists();
      error InvalidRecipient();
      error InvalidCaller();
      error VestingConfigNotSet();
      error InvalidVestingConfig();
      error EmptyArray();
      error InvalidUserVestingId();// SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      import "../Errors.sol";
      interface IDistributor {
          function initClaim(address caller, bytes calldata proofs, address recipient) external;
          function claim(address caller, bytes32 userVestingId, address recipient) external;
      }// SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
      import "../interfaces/IDistributor.sol";
      import "../Errors.sol";
      /**
       * @title BatchDistributor
       * @author @trmaphi
       * @notice This contract is used to claim airdrops for multiple users in one call.
       */
      contract BatchDistributor is ReentrancyGuard {
          struct BatchClaimParams {
              address distributorContract;
              bool isInit;
              bytes32 userVestingId;
              bytes proof;
          }
          event BatchClaimed(address indexed caller, address[] distributors, address recipient);
          constructor() {
          }
          /**
           * Claim for multiple airdrops
           * @param params BatchClaimParams[]
           * @param recipient address
           */
          function batchClaim(BatchClaimParams[] calldata params, address recipient) external nonReentrant {
              if (params.length == 0) revert EmptyArray();
              if (recipient != msg.sender) revert InvalidRecipient();
              address[] memory distributors = new address[](params.length);
              for (uint256 i = 0; i < params.length; i++) {
                  BatchClaimParams memory param = params[i];
                  distributors[i] = param.distributorContract;
                  IDistributor distributor = IDistributor(param.distributorContract);
                  
                  if (param.isInit) {
                      if (param.proof.length == 0) revert InvalidProofs();
                      distributor.initClaim(
                          msg.sender,
                          param.proof,
                          recipient
                      );
                  } else {
                      distributor.claim(
                          msg.sender,
                          param.userVestingId,
                          recipient
                      );
                  }
              }
              emit BatchClaimed(msg.sender, distributors, recipient);
          }
      }

      File 2 of 3: UprisingAirdropDistributorAfterInit
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      pragma solidity ^0.8.20;
      import {Context} from "../utils/Context.sol";
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is set to the address provided by the deployer. This can
       * later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
          /**
           * @dev The caller account is not authorized to perform an operation.
           */
          error OwnableUnauthorizedAccount(address account);
          /**
           * @dev The owner is not a valid owner account. (eg. `address(0)`)
           */
          error OwnableInvalidOwner(address owner);
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
          /**
           * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
           */
          constructor(address initialOwner) {
              if (initialOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(initialOwner);
          }
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              if (owner() != _msgSender()) {
                  revert OwnableUnauthorizedAccount(_msgSender());
              }
          }
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              if (newOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(newOwner);
          }
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "./IERC20.sol";
      import {IERC165} from "./IERC165.sol";
      /**
       * @title IERC1363
       * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
       *
       * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
       * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
       */
      interface IERC1363 is IERC20, IERC165 {
          /*
           * Note: the ERC-165 identifier for this interface is 0xb0202a11.
           * 0xb0202a11 ===
           *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
           *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
           *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
           *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
           *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
           */
          /**
           * @dev Moves a `value` amount of tokens from the caller's account to `to`
           * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
           * @param to The address which you want to transfer to.
           * @param value The amount of tokens to be transferred.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function transferAndCall(address to, uint256 value) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from the caller's account to `to`
           * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
           * @param to The address which you want to transfer to.
           * @param value The amount of tokens to be transferred.
           * @param data Additional data with no specified format, sent in call to `to`.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
           * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
           * @param from The address which you want to send tokens from.
           * @param to The address which you want to transfer to.
           * @param value The amount of tokens to be transferred.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
           * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
           * @param from The address which you want to send tokens from.
           * @param to The address which you want to transfer to.
           * @param value The amount of tokens to be transferred.
           * @param data Additional data with no specified format, sent in call to `to`.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
          /**
           * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
           * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
           * @param spender The address which will spend the funds.
           * @param value The amount of tokens to be spent.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function approveAndCall(address spender, uint256 value) external returns (bool);
          /**
           * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
           * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
           * @param spender The address which will spend the funds.
           * @param value The amount of tokens to be spent.
           * @param data Additional data with no specified format, sent in call to `spender`.
           * @return A boolean value indicating whether the operation succeeded unless throwing.
           */
          function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
      pragma solidity ^0.8.20;
      import {IERC165} from "../utils/introspection/IERC165.sol";
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "../token/ERC20/IERC20.sol";
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Interface of the ERC-20 standard as defined in the ERC.
       */
      interface IERC20 {
          /**
           * @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);
          /**
           * @dev Returns the value of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the value of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves a `value` amount of tokens from the caller's account to `to`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the
           * allowance mechanism. `value` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address from, address to, uint256 value) external returns (bool);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "../IERC20.sol";
      import {IERC1363} from "../../../interfaces/IERC1363.sol";
      import {Address} from "../../../utils/Address.sol";
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC-20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          /**
           * @dev An operation with an ERC-20 token failed.
           */
          error SafeERC20FailedOperation(address token);
          /**
           * @dev Indicates a failed `decreaseAllowance` request.
           */
          error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
          /**
           * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
          }
          /**
           * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
           * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
           */
          function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
          }
          /**
           * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           *
           * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
           * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
           * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
           * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
           */
          function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 oldAllowance = token.allowance(address(this), spender);
              forceApprove(token, spender, oldAllowance + value);
          }
          /**
           * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
           * value, non-reverting calls are assumed to be successful.
           *
           * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
           * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
           * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
           * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
           */
          function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
              unchecked {
                  uint256 currentAllowance = token.allowance(address(this), spender);
                  if (currentAllowance < requestedDecrease) {
                      revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
                  }
                  forceApprove(token, spender, currentAllowance - requestedDecrease);
              }
          }
          /**
           * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
           * to be set to zero before setting it to a non-zero value, such as USDT.
           *
           * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
           * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
           * set here.
           */
          function forceApprove(IERC20 token, address spender, uint256 value) internal {
              bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
              if (!_callOptionalReturnBool(token, approvalCall)) {
                  _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
                  _callOptionalReturn(token, approvalCall);
              }
          }
          /**
           * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
           * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
           * targeting contracts.
           *
           * Reverts if the returned value is other than `true`.
           */
          function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
              if (to.code.length == 0) {
                  safeTransfer(token, to, value);
              } else if (!token.transferAndCall(to, value, data)) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
          /**
           * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
           * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
           * targeting contracts.
           *
           * Reverts if the returned value is other than `true`.
           */
          function transferFromAndCallRelaxed(
              IERC1363 token,
              address from,
              address to,
              uint256 value,
              bytes memory data
          ) internal {
              if (to.code.length == 0) {
                  safeTransferFrom(token, from, to, value);
              } else if (!token.transferFromAndCall(from, to, value, data)) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
          /**
           * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
           * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
           * targeting contracts.
           *
           * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
           * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
           * once without retrying, and relies on the returned value to be true.
           *
           * Reverts if the returned value is other than `true`.
           */
          function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
              if (to.code.length == 0) {
                  forceApprove(token, to, value);
              } else if (!token.approveAndCall(to, value, data)) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              uint256 returnSize;
              uint256 returnValue;
              assembly ("memory-safe") {
                  let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                  // bubble errors
                  if iszero(success) {
                      let ptr := mload(0x40)
                      returndatacopy(ptr, 0, returndatasize())
                      revert(ptr, returndatasize())
                  }
                  returnSize := returndatasize()
                  returnValue := mload(0)
              }
              if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
           */
          function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
              bool success;
              uint256 returnSize;
              uint256 returnValue;
              assembly ("memory-safe") {
                  success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                  returnSize := returndatasize()
                  returnValue := mload(0)
              }
              return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol)
      pragma solidity ^0.8.20;
      import {Errors} from "./Errors.sol";
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev There's no code at `target` (it is not a contract).
           */
          error AddressEmptyCode(address target);
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              if (address(this).balance < amount) {
                  revert Errors.InsufficientBalance(address(this).balance, amount);
              }
              (bool success, ) = recipient.call{value: amount}("");
              if (!success) {
                  revert Errors.FailedCall();
              }
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason or custom error, it is bubbled
           * up by this function (like regular Solidity function calls). However, if
           * the call reverted with no returned reason, this function reverts with a
           * {Errors.FailedCall} error.
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           */
          function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
              if (address(this).balance < value) {
                  revert Errors.InsufficientBalance(address(this).balance, value);
              }
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
           * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
           * of an unsuccessful call.
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata
          ) internal view returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  // only check if target is a contract if the call was successful and the return data is empty
                  // otherwise we already know that it was a contract
                  if (returndata.length == 0 && target.code.length == 0) {
                      revert AddressEmptyCode(target);
                  }
                  return returndata;
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
           * revert reason or with a default {Errors.FailedCall} error.
           */
          function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  return returndata;
              }
          }
          /**
           * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
           */
          function _revert(bytes memory returndata) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  assembly ("memory-safe") {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert Errors.FailedCall();
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @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;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
      pragma solidity ^0.8.20;
      /**
       * @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
          }
          /**
           * @dev The signature derives the `address(0)`.
           */
          error ECDSAInvalidSignature();
          /**
           * @dev The signature has an invalid length.
           */
          error ECDSAInvalidSignatureLength(uint256 length);
          /**
           * @dev The signature has an S value that is in the upper half order.
           */
          error ECDSAInvalidSignatureS(bytes32 s);
          /**
           * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
           * return address(0) without also returning an error description. Errors are documented using an enum (error type)
           * and a bytes32 providing additional information about the error.
           *
           * If no error is returned, then the address can be used for verification purposes.
           *
           * The `ecrecover` EVM precompile 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 {MessageHashUtils-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]
           */
          function tryRecover(
              bytes32 hash,
              bytes memory signature
          ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
              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 ("memory-safe") {
                      r := mload(add(signature, 0x20))
                      s := mload(add(signature, 0x40))
                      v := byte(0, mload(add(signature, 0x60)))
                  }
                  return tryRecover(hash, v, r, s);
              } else {
                  return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
              }
          }
          /**
           * @dev Returns the address that signed a hashed message (`hash`) with
           * `signature`. This address can then be used for verification purposes.
           *
           * The `ecrecover` EVM precompile 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 {MessageHashUtils-toEthSignedMessageHash} on it.
           */
          function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
              (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
              _throwError(error, errorArg);
              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[ERC-2098 short signatures]
           */
          function tryRecover(
              bytes32 hash,
              bytes32 r,
              bytes32 vs
          ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
              unchecked {
                  bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                  // We do not check for an overflow here since the shift operation results in 0 or 1.
                  uint8 v = uint8((uint256(vs) >> 255) + 27);
                  return tryRecover(hash, v, r, s);
              }
          }
          /**
           * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
           */
          function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
              (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
              _throwError(error, errorArg);
              return recovered;
          }
          /**
           * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
           * `r` and `s` signature fields separately.
           */
          function tryRecover(
              bytes32 hash,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
              // 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, s);
              }
              // 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, bytes32(0));
              }
              return (signer, RecoverError.NoError, bytes32(0));
          }
          /**
           * @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, bytes32 errorArg) = tryRecover(hash, v, r, s);
              _throwError(error, errorArg);
              return recovered;
          }
          /**
           * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
           */
          function _throwError(RecoverError error, bytes32 errorArg) private pure {
              if (error == RecoverError.NoError) {
                  return; // no error: do nothing
              } else if (error == RecoverError.InvalidSignature) {
                  revert ECDSAInvalidSignature();
              } else if (error == RecoverError.InvalidSignatureLength) {
                  revert ECDSAInvalidSignatureLength(uint256(errorArg));
              } else if (error == RecoverError.InvalidSignatureS) {
                  revert ECDSAInvalidSignatureS(errorArg);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/Hashes.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Library of standard hash functions.
       *
       * _Available since v5.1._
       */
      library Hashes {
          /**
           * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
           *
           * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
           */
          function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
              return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
          }
          /**
           * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
           */
          function _efficientKeccak256(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
              assembly ("memory-safe") {
                  mstore(0x00, a)
                  mstore(0x20, b)
                  value := keccak256(0x00, 0x40)
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MerkleProof.sol)
      // This file was procedurally generated from scripts/generate/templates/MerkleProof.js.
      pragma solidity ^0.8.20;
      import {Hashes} from "./Hashes.sol";
      /**
       * @dev These functions deal with verification of Merkle Tree proofs.
       *
       * The tree and the proofs can be generated using our
       * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
       * You will find a quickstart guide in the readme.
       *
       * WARNING: You should avoid using leaf values that are 64 bytes long prior to
       * hashing, or use a hash function other than keccak256 for hashing leaves.
       * This is because the concatenation of a sorted pair of internal nodes in
       * the Merkle tree could be reinterpreted as a leaf value.
       * OpenZeppelin's JavaScript library generates Merkle trees that are safe
       * against this attack out of the box.
       *
       * IMPORTANT: Consider memory side-effects when using custom hashing functions
       * that access memory in an unsafe way.
       *
       * NOTE: This library supports proof verification for merkle trees built using
       * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving
       * leaf inclusion in trees built using non-commutative hashing functions requires
       * additional logic that is not supported by this library.
       */
      library MerkleProof {
          /**
           *@dev The multiproof provided is not valid.
           */
          error MerkleProofInvalidMultiproof();
          /**
           * @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.
           *
           * This version handles proofs in memory with the default hashing function.
           */
          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 Merkle 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 leaves & pre-images are assumed to be sorted.
           *
           * This version handles proofs in memory with the default hashing function.
           */
          function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @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.
           *
           * This version handles proofs in memory with a custom hashing function.
           */
          function verify(
              bytes32[] memory proof,
              bytes32 root,
              bytes32 leaf,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bool) {
              return processProof(proof, leaf, hasher) == root;
          }
          /**
           * @dev Returns the rebuilt hash obtained by traversing a Merkle 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 leaves & pre-images are assumed to be sorted.
           *
           * This version handles proofs in memory with a custom hashing function.
           */
          function processProof(
              bytes32[] memory proof,
              bytes32 leaf,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = hasher(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @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.
           *
           * This version handles proofs in calldata with the default hashing function.
           */
          function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
              return processProofCalldata(proof, leaf) == root;
          }
          /**
           * @dev Returns the rebuilt hash obtained by traversing a Merkle 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 leaves & pre-images are assumed to be sorted.
           *
           * This version handles proofs in calldata with the default hashing function.
           */
          function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @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.
           *
           * This version handles proofs in calldata with a custom hashing function.
           */
          function verifyCalldata(
              bytes32[] calldata proof,
              bytes32 root,
              bytes32 leaf,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bool) {
              return processProofCalldata(proof, leaf, hasher) == root;
          }
          /**
           * @dev Returns the rebuilt hash obtained by traversing a Merkle 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 leaves & pre-images are assumed to be sorted.
           *
           * This version handles proofs in calldata with a custom hashing function.
           */
          function processProofCalldata(
              bytes32[] calldata proof,
              bytes32 leaf,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = hasher(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
           *
           * This version handles multiproofs in memory with the default hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
           * The `leaves` must be validated independently. See {processMultiProof}.
           */
          function multiProofVerify(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32 root,
              bytes32[] memory leaves
          ) internal pure returns (bool) {
              return processMultiProof(proof, proofFlags, leaves) == root;
          }
          /**
           * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
           * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
           * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
           * respectively.
           *
           * This version handles multiproofs in memory with the default hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
           * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
           * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
           *
           * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
           * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
           * validating the leaves elsewhere.
           */
          function processMultiProof(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32[] memory leaves
          ) internal pure returns (bytes32 merkleRoot) {
              // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the Merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 proofFlagsLen = proofFlags.length;
              // Check proof validity.
              if (leavesLen + proof.length != proofFlagsLen + 1) {
                  revert MerkleProofInvalidMultiproof();
              }
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](proofFlagsLen);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < proofFlagsLen; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i]
                      ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                      : proof[proofPos++];
                  hashes[i] = Hashes.commutativeKeccak256(a, b);
              }
              if (proofFlagsLen > 0) {
                  if (proofPos != proof.length) {
                      revert MerkleProofInvalidMultiproof();
                  }
                  unchecked {
                      return hashes[proofFlagsLen - 1];
                  }
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
          /**
           * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
           *
           * This version handles multiproofs in memory with a custom hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
           * The `leaves` must be validated independently. See {processMultiProof}.
           */
          function multiProofVerify(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32 root,
              bytes32[] memory leaves,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bool) {
              return processMultiProof(proof, proofFlags, leaves, hasher) == root;
          }
          /**
           * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
           * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
           * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
           * respectively.
           *
           * This version handles multiproofs in memory with a custom hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
           * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
           * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
           *
           * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
           * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
           * validating the leaves elsewhere.
           */
          function processMultiProof(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32[] memory leaves,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bytes32 merkleRoot) {
              // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the Merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 proofFlagsLen = proofFlags.length;
              // Check proof validity.
              if (leavesLen + proof.length != proofFlagsLen + 1) {
                  revert MerkleProofInvalidMultiproof();
              }
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](proofFlagsLen);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < proofFlagsLen; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i]
                      ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                      : proof[proofPos++];
                  hashes[i] = hasher(a, b);
              }
              if (proofFlagsLen > 0) {
                  if (proofPos != proof.length) {
                      revert MerkleProofInvalidMultiproof();
                  }
                  unchecked {
                      return hashes[proofFlagsLen - 1];
                  }
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
          /**
           * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
           *
           * This version handles multiproofs in calldata with the default hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
           * The `leaves` must be validated independently. See {processMultiProofCalldata}.
           */
          function multiProofVerifyCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32 root,
              bytes32[] memory leaves
          ) internal pure returns (bool) {
              return processMultiProofCalldata(proof, proofFlags, leaves) == root;
          }
          /**
           * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
           * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
           * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
           * respectively.
           *
           * This version handles multiproofs in calldata with the default hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
           * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
           * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
           *
           * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
           * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
           * validating the leaves elsewhere.
           */
          function processMultiProofCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32[] memory leaves
          ) internal pure returns (bytes32 merkleRoot) {
              // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the Merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 proofFlagsLen = proofFlags.length;
              // Check proof validity.
              if (leavesLen + proof.length != proofFlagsLen + 1) {
                  revert MerkleProofInvalidMultiproof();
              }
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](proofFlagsLen);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < proofFlagsLen; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i]
                      ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                      : proof[proofPos++];
                  hashes[i] = Hashes.commutativeKeccak256(a, b);
              }
              if (proofFlagsLen > 0) {
                  if (proofPos != proof.length) {
                      revert MerkleProofInvalidMultiproof();
                  }
                  unchecked {
                      return hashes[proofFlagsLen - 1];
                  }
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
          /**
           * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
           *
           * This version handles multiproofs in calldata with a custom hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
           * The `leaves` must be validated independently. See {processMultiProofCalldata}.
           */
          function multiProofVerifyCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32 root,
              bytes32[] memory leaves,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bool) {
              return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == root;
          }
          /**
           * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
           * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
           * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
           * respectively.
           *
           * This version handles multiproofs in calldata with a custom hashing function.
           *
           * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
           * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
           * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
           *
           * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
           * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
           * validating the leaves elsewhere.
           */
          function processMultiProofCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32[] memory leaves,
              function(bytes32, bytes32) view returns (bytes32) hasher
          ) internal view returns (bytes32 merkleRoot) {
              // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the Merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 proofFlagsLen = proofFlags.length;
              // Check proof validity.
              if (leavesLen + proof.length != proofFlagsLen + 1) {
                  revert MerkleProofInvalidMultiproof();
              }
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](proofFlagsLen);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < proofFlagsLen; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i]
                      ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                      : proof[proofPos++];
                  hashes[i] = hasher(a, b);
              }
              if (proofFlagsLen > 0) {
                  if (proofPos != proof.length) {
                      revert MerkleProofInvalidMultiproof();
                  }
                  unchecked {
                      return hashes[proofFlagsLen - 1];
                  }
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Collection of common custom errors used in multiple contracts
       *
       * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
       * It is recommended to avoid relying on the error API for critical functionality.
       *
       * _Available since v5.1._
       */
      library Errors {
          /**
           * @dev The ETH balance of the account is not enough to perform the operation.
           */
          error InsufficientBalance(uint256 balance, uint256 needed);
          /**
           * @dev A call to an address target failed. The target may have reverted.
           */
          error FailedCall();
          /**
           * @dev The deployment failed.
           */
          error FailedDeployment();
          /**
           * @dev A necessary precompile is missing.
           */
          error MissingPrecompile(address);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Interface of the ERC-165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[ERC].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      // SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      error InvalidSignature();
      error AlreadyClaimed();
      error ZeroAddress();
      error DeadlinePassed();
      error InvalidProofs();
      error RootHashAlreadySet();
      error SlotExists();
      error InvalidRecipient();
      error InvalidCaller();
      error VestingConfigNotSet();
      error InvalidVestingConfig();
      error EmptyArray();
      error InvalidUserVestingId();// SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      import "@openzeppelin/contracts/access/Ownable.sol";
      import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
      import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
      import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
      import "../VestingUtils.sol";
      import "../Errors.sol";
      interface IOldDistributor {
          function slotInfos(bytes32 userVestingId) external view returns (uint256, uint256, uint128, uint128, uint32, uint32, uint32, bool);
      }
      /**
       * @title UprisingAirdropDistributor
       * @author @trmaphi
       * @notice This contract is used to patch the old uprising airdrop distributor.
       */
      contract UprisingAirdropDistributorAfterInit is Ownable {
          /// From Distributor    
          using SafeERC20 for IERC20;
          address public batchDistributor;
          IERC20 public immutable paymentToken;
          IOldDistributor public oldDistributor;
          // userVestingId => SlotInfo
          mapping(bytes32 => SlotInfo) public _slotInfos;
          // 10_000 = 100%
          uint256 public constant BASIC_POINT_DECIMALS = 10_000;
          struct VestingConfig {
              uint32 initClaimPercent;
              uint32 intervalPercent;
              uint32 intervalDays;
              uint128 initDeadline;
          }
          
          struct SlotInfo {
              uint256 amount;
              uint256 claimed;
              uint128 initDeadline; // The timestamp of the deadline of the airdrop even with amount still available, user won't be able to claim
              uint128 startTime;
              uint32 initClaimPercent;
              uint32 intervalPercent;
              uint32 intervalDays;
              bool initialized;
          }
          
          event DistributorUpdated(address indexed oldDistributor, address indexed newDistributor);
          event Claimed(address indexed caller, bytes32 indexed userVestingId, address indexed recipient, uint256 amount);
          /// From Distributor
          event SlotInitialized(address indexed initializer, address indexed recipient, uint256 amount);
          constructor(address _paymentToken, address _oldDistributor) Ownable(msg.sender) {
              if (_paymentToken == address(0) || _oldDistributor == address(0)) revert ZeroAddress();
              paymentToken = IERC20(_paymentToken);
              oldDistributor = IOldDistributor(_oldDistributor);
          }
          modifier onlyBatchDistributor() {
              require(batchDistributor == msg.sender, "Caller is not the batch distributor");
              _;
          }
          /**
           * Get the slot info of a user, using the old distributor if the slot is not initialized
           * @param userVestingId The user vesting id
           * @return The slot info
           */
          function slotInfos(bytes32 userVestingId) external view returns (SlotInfo memory) {
              if (_slotInfos[userVestingId].amount == 0) {
                  (
                      uint256 amount,
                      uint256 claimed,
                      uint128 initDeadline,
                      uint128 startTime,
                      uint32 initClaimPercent,
                      uint32 intervalPercent,
                      uint32 intervalDays,
                      bool initialized
                  ) = oldDistributor.slotInfos(userVestingId);
                  return SlotInfo({
                      amount: amount,
                      claimed: claimed,
                      initDeadline: initDeadline,
                      startTime: startTime,
                      initClaimPercent: initClaimPercent,
                      intervalPercent: intervalPercent,
                      intervalDays: intervalDays,
                      initialized: initialized
                  });
              }
              
              return _slotInfos[userVestingId];
          }
          /**
           * @notice Claim the airdrop
           */
          function setBatchDistributor(address newDistributor) external onlyOwner {        
              batchDistributor = newDistributor;
              emit DistributorUpdated(batchDistributor, newDistributor);
          }
          /**
           * @notice Initialize the claim for a user
           * @param caller The caller of the function forwarded from the batch distributor
           * @param proofs The merkle proof for the user
           * @param recipient The recipient of the airdrop
           */
          function initClaim(address caller, bytes calldata proofs, address recipient) external onlyBatchDistributor {
              revert DeadlinePassed();
          }
          /**
           * @notice Claim the airdrop
           * @dev
           * - Requirement:
           *      - Caller MUST be the one initialized the claim
           */
          function _verifyCaller(address caller, bytes32 userVestingId) internal view {
              if (caller != VestingUtils.bytes32ToAddress(userVestingId)) revert InvalidCaller();
          }
          /**
           * @notice Claim the airdrop for a user
           * @param caller The caller of the function forwarded from the batch distributor
           * @param userVestingId The user vesting id
           * @param recipient The recipient of the airdrop
           */
          function claim(address caller, bytes32 userVestingId, address recipient) external onlyBatchDistributor {
              SlotInfo memory slot = this.slotInfos(userVestingId);
              if (_slotInfos[userVestingId].amount == 0) {
                  _slotInfos[userVestingId] = slot;
              }
              // Check if the slot is initialized
              if (!slot.initialized) revert DeadlinePassed();
              if (_slotInfos[userVestingId].claimed >= _slotInfos[userVestingId].amount) revert AlreadyClaimed();
              _verifyCaller(caller, userVestingId);
              uint256 claimAmount = _calculateClaimAmount(userVestingId);
              if (claimAmount == 0) revert AlreadyClaimed();
              _transferToRecipient(userVestingId, recipient, claimAmount);
              emit Claimed(caller, userVestingId, recipient, claimAmount);
          }
          /**
           * @notice Calculate the claimable amount for a user
           * @param userVestingId The user vesting id
           * @return The claimable amount
           */
          function _calculateClaimAmount(bytes32 userVestingId) internal view returns (uint256) {
              SlotInfo memory slot = _slotInfos[userVestingId];        
              // Calculate time elapsed since vesting started
              uint256 timeElapsed = (block.timestamp - slot.startTime) / (slot.intervalDays * 1 days);
              
              // Calculate total percentage
              uint256 currentPercent = (timeElapsed * slot.intervalPercent) + slot.initClaimPercent;
              if (currentPercent > BASIC_POINT_DECIMALS) currentPercent = BASIC_POINT_DECIMALS;
              // Calculate total vested amount
              uint256 totalVestedAmount = (slot.amount * currentPercent) / BASIC_POINT_DECIMALS;
              
              // Calculate remaining claimable amount
              uint256 amountToClaim = totalVestedAmount - slot.claimed;
              
              return amountToClaim;
          }
          /**
           * @notice Transfer the airdrop to the recipient
           * @param userVestingId The user vesting id
           * @param recipient The recipient of the airdrop
           * @param amount The amount to transfer
           */
          function _transferToRecipient(bytes32 userVestingId, address recipient, uint256 amount) internal {
              _slotInfos[userVestingId].claimed += amount;
              paymentToken.safeTransfer(recipient, amount);
          }
          /**
           * @notice Emergency function to recover wrong tokens
           * @param _token The token to recover
           * @param _amount The amount to recover
           */
          function recoverToken(address _token, uint256 _amount) external onlyOwner {
              IERC20(_token).safeTransfer(owner(), _amount);
          }
      }// SPDX-License-Identifier: UNLICENSED
      pragma solidity ^0.8.20;
      library VestingUtils {
          /**
           * @dev Converts an address to bytes32.
           * @param _addr The address to convert.
           * @return The bytes32 representation of the address.
           */
          function addressToBytes32(address _addr) internal pure returns (bytes32) {
              return bytes32(uint256(uint160(_addr)));
          }
          /**
           * @dev Converts bytes32 to an address.
           * @param _b The bytes32 value to convert.
           * @return The address representation of bytes32.
           */
          function bytes32ToAddress(bytes32 _b) internal pure returns (address) {
              return address(uint160(uint256(_b)));
          }
      }

      File 3 of 3: KIP
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.22;
      import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
      contract KIP is ERC20 {
          constructor(address beneficiary) ERC20("KIP Protocol", "KIP") {
              _mint(beneficiary, 10000000000 * 10 ** decimals());
          }
      }// SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/ERC20.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "./IERC20.sol";
      import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
      import {Context} from "../../utils/Context.sol";
      import {IERC20Errors} from "../../interfaces/draft-IERC6093.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}.
       *
       * TIP: For a detailed writeup see our guide
       * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * The default value of {decimals} is 18. To change this, you should override
       * this function so it returns a different value.
       *
       * 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 ERC-20
       * applications.
       */
      abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
          mapping(address account => uint256) private _balances;
          mapping(address account => mapping(address spender => uint256)) private _allowances;
          uint256 private _totalSupply;
          string private _name;
          string private _symbol;
          /**
           * @dev Sets the values for {name} and {symbol}.
           *
           * 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 returns (string memory) {
              return _name;
          }
          /**
           * @dev Returns the symbol of the token, usually a shorter version of the
           * name.
           */
          function symbol() public view virtual returns (string memory) {
              return _symbol;
          }
          /**
           * @dev Returns the number of decimals used to get its user representation.
           * For example, if `decimals` equals `2`, a balance of `505` tokens should
           * be displayed to a user as `5.05` (`505 / 10 ** 2`).
           *
           * Tokens usually opt for a value of 18, imitating the relationship between
           * Ether and Wei. This is the default value returned by this function, unless
           * it's 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 returns (uint8) {
              return 18;
          }
          /**
           * @dev See {IERC20-totalSupply}.
           */
          function totalSupply() public view virtual returns (uint256) {
              return _totalSupply;
          }
          /**
           * @dev See {IERC20-balanceOf}.
           */
          function balanceOf(address account) public view virtual returns (uint256) {
              return _balances[account];
          }
          /**
           * @dev See {IERC20-transfer}.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           * - the caller must have a balance of at least `value`.
           */
          function transfer(address to, uint256 value) public virtual returns (bool) {
              address owner = _msgSender();
              _transfer(owner, to, value);
              return true;
          }
          /**
           * @dev See {IERC20-allowance}.
           */
          function allowance(address owner, address spender) public view virtual returns (uint256) {
              return _allowances[owner][spender];
          }
          /**
           * @dev See {IERC20-approve}.
           *
           * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
           * `transferFrom`. This is semantically equivalent to an infinite approval.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function approve(address spender, uint256 value) public virtual returns (bool) {
              address owner = _msgSender();
              _approve(owner, spender, value);
              return true;
          }
          /**
           * @dev See {IERC20-transferFrom}.
           *
           * Skips emitting an {Approval} event indicating an allowance update. This is not
           * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
           *
           * NOTE: Does not update the allowance if the current allowance
           * is the maximum `uint256`.
           *
           * Requirements:
           *
           * - `from` and `to` cannot be the zero address.
           * - `from` must have a balance of at least `value`.
           * - the caller must have allowance for ``from``'s tokens of at least
           * `value`.
           */
          function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
              address spender = _msgSender();
              _spendAllowance(from, spender, value);
              _transfer(from, to, value);
              return true;
          }
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to`.
           *
           * 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.
           *
           * NOTE: This function is not virtual, {_update} should be overridden instead.
           */
          function _transfer(address from, address to, uint256 value) internal {
              if (from == address(0)) {
                  revert ERC20InvalidSender(address(0));
              }
              if (to == address(0)) {
                  revert ERC20InvalidReceiver(address(0));
              }
              _update(from, to, value);
          }
          /**
           * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
           * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
           * this function.
           *
           * Emits a {Transfer} event.
           */
          function _update(address from, address to, uint256 value) internal virtual {
              if (from == address(0)) {
                  // Overflow check required: The rest of the code assumes that totalSupply never overflows
                  _totalSupply += value;
              } else {
                  uint256 fromBalance = _balances[from];
                  if (fromBalance < value) {
                      revert ERC20InsufficientBalance(from, fromBalance, value);
                  }
                  unchecked {
                      // Overflow not possible: value <= fromBalance <= totalSupply.
                      _balances[from] = fromBalance - value;
                  }
              }
              if (to == address(0)) {
                  unchecked {
                      // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                      _totalSupply -= value;
                  }
              } else {
                  unchecked {
                      // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                      _balances[to] += value;
                  }
              }
              emit Transfer(from, to, value);
          }
          /**
           * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
           * Relies on the `_update` mechanism
           *
           * Emits a {Transfer} event with `from` set to the zero address.
           *
           * NOTE: This function is not virtual, {_update} should be overridden instead.
           */
          function _mint(address account, uint256 value) internal {
              if (account == address(0)) {
                  revert ERC20InvalidReceiver(address(0));
              }
              _update(address(0), account, value);
          }
          /**
           * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
           * Relies on the `_update` mechanism.
           *
           * Emits a {Transfer} event with `to` set to the zero address.
           *
           * NOTE: This function is not virtual, {_update} should be overridden instead
           */
          function _burn(address account, uint256 value) internal {
              if (account == address(0)) {
                  revert ERC20InvalidSender(address(0));
              }
              _update(account, address(0), value);
          }
          /**
           * @dev Sets `value` 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.
           *
           * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
           */
          function _approve(address owner, address spender, uint256 value) internal {
              _approve(owner, spender, value, true);
          }
          /**
           * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
           *
           * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
           * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
           * `Approval` event during `transferFrom` operations.
           *
           * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
           * true using the following override:
           *
           * ```solidity
           * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
           *     super._approve(owner, spender, value, true);
           * }
           * ```
           *
           * Requirements are the same as {_approve}.
           */
          function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
              if (owner == address(0)) {
                  revert ERC20InvalidApprover(address(0));
              }
              if (spender == address(0)) {
                  revert ERC20InvalidSpender(address(0));
              }
              _allowances[owner][spender] = value;
              if (emitEvent) {
                  emit Approval(owner, spender, value);
              }
          }
          /**
           * @dev Updates `owner` s allowance for `spender` based on spent `value`.
           *
           * Does not update the allowance value in case of infinite allowance.
           * Revert if not enough allowance is available.
           *
           * Does not emit an {Approval} event.
           */
          function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
              uint256 currentAllowance = allowance(owner, spender);
              if (currentAllowance != type(uint256).max) {
                  if (currentAllowance < value) {
                      revert ERC20InsufficientAllowance(spender, currentAllowance, value);
                  }
                  unchecked {
                      _approve(owner, spender, currentAllowance - value, false);
                  }
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Standard ERC-20 Errors
       * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
       */
      interface IERC20Errors {
          /**
           * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           * @param balance Current balance for the interacting account.
           * @param needed Minimum amount required to perform a transfer.
           */
          error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
          /**
           * @dev Indicates a failure with the token `sender`. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           */
          error ERC20InvalidSender(address sender);
          /**
           * @dev Indicates a failure with the token `receiver`. Used in transfers.
           * @param receiver Address to which tokens are being transferred.
           */
          error ERC20InvalidReceiver(address receiver);
          /**
           * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
           * @param spender Address that may be allowed to operate on tokens without being their owner.
           * @param allowance Amount of tokens a `spender` is allowed to operate with.
           * @param needed Minimum amount required to perform a transfer.
           */
          error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
          /**
           * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
           * @param approver Address initiating an approval operation.
           */
          error ERC20InvalidApprover(address approver);
          /**
           * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
           * @param spender Address that may be allowed to operate on tokens without being their owner.
           */
          error ERC20InvalidSpender(address spender);
      }
      /**
       * @dev Standard ERC-721 Errors
       * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
       */
      interface IERC721Errors {
          /**
           * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
           * Used in balance queries.
           * @param owner Address of the current owner of a token.
           */
          error ERC721InvalidOwner(address owner);
          /**
           * @dev Indicates a `tokenId` whose `owner` is the zero address.
           * @param tokenId Identifier number of a token.
           */
          error ERC721NonexistentToken(uint256 tokenId);
          /**
           * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           * @param tokenId Identifier number of a token.
           * @param owner Address of the current owner of a token.
           */
          error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
          /**
           * @dev Indicates a failure with the token `sender`. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           */
          error ERC721InvalidSender(address sender);
          /**
           * @dev Indicates a failure with the token `receiver`. Used in transfers.
           * @param receiver Address to which tokens are being transferred.
           */
          error ERC721InvalidReceiver(address receiver);
          /**
           * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
           * @param operator Address that may be allowed to operate on tokens without being their owner.
           * @param tokenId Identifier number of a token.
           */
          error ERC721InsufficientApproval(address operator, uint256 tokenId);
          /**
           * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
           * @param approver Address initiating an approval operation.
           */
          error ERC721InvalidApprover(address approver);
          /**
           * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
           * @param operator Address that may be allowed to operate on tokens without being their owner.
           */
          error ERC721InvalidOperator(address operator);
      }
      /**
       * @dev Standard ERC-1155 Errors
       * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
       */
      interface IERC1155Errors {
          /**
           * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           * @param balance Current balance for the interacting account.
           * @param needed Minimum amount required to perform a transfer.
           * @param tokenId Identifier number of a token.
           */
          error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
          /**
           * @dev Indicates a failure with the token `sender`. Used in transfers.
           * @param sender Address whose tokens are being transferred.
           */
          error ERC1155InvalidSender(address sender);
          /**
           * @dev Indicates a failure with the token `receiver`. Used in transfers.
           * @param receiver Address to which tokens are being transferred.
           */
          error ERC1155InvalidReceiver(address receiver);
          /**
           * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
           * @param operator Address that may be allowed to operate on tokens without being their owner.
           * @param owner Address of the current owner of a token.
           */
          error ERC1155MissingApprovalForAll(address operator, address owner);
          /**
           * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
           * @param approver Address initiating an approval operation.
           */
          error ERC1155InvalidApprover(address approver);
          /**
           * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
           * @param operator Address that may be allowed to operate on tokens without being their owner.
           */
          error ERC1155InvalidOperator(address operator);
          /**
           * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
           * Used in batch transfers.
           * @param idsLength Length of the array of token identifiers
           * @param valuesLength Length of the array of token amounts
           */
          error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      pragma solidity ^0.8.20;
      /**
       * @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;
          }
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
      pragma solidity ^0.8.20;
      import {IERC20} from "../IERC20.sol";
      /**
       * @dev Interface for the optional metadata functions from the ERC-20 standard.
       */
      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
      // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
      pragma solidity ^0.8.20;
      /**
       * @dev Interface of the ERC-20 standard as defined in the ERC.
       */
      interface IERC20 {
          /**
           * @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);
          /**
           * @dev Returns the value of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the value of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves a `value` amount of tokens from the caller's account to `to`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool);
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the
           * allowance mechanism. `value` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address from, address to, uint256 value) external returns (bool);
      }