creation_sourcecode: // File: @openzeppelin/contracts/utils/math/SafeCast.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
  // This file was procedurally generated from scripts/generate/templates/SafeCast.js.
  
  pragma solidity ^0.8.20;
  
  /**
   * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
   * checks.
   *
   * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
   * easily result in undesired exploitation or bugs, since developers usually
   * assume that overflows raise errors. `SafeCast` restores this intuition by
   * reverting the transaction when such an operation overflows.
   *
   * Using this library instead of the unchecked operations eliminates an entire
   * class of bugs, so it's recommended to use it always.
   */
  library SafeCast {
      /**
       * @dev Value doesn't fit in an uint of `bits` size.
       */
      error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
  
      /**
       * @dev An int value doesn't fit in an uint of `bits` size.
       */
      error SafeCastOverflowedIntToUint(int256 value);
  
      /**
       * @dev Value doesn't fit in an int of `bits` size.
       */
      error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
  
      /**
       * @dev An uint value doesn't fit in an int of `bits` size.
       */
      error SafeCastOverflowedUintToInt(uint256 value);
  
      /**
       * @dev Returns the downcasted uint248 from uint256, reverting on
       * overflow (when the input is greater than largest uint248).
       *
       * Counterpart to Solidity's `uint248` operator.
       *
       * Requirements:
       *
       * - input must fit into 248 bits
       */
      function toUint248(uint256 value) internal pure returns (uint248) {
          if (value > type(uint248).max) {
              revert SafeCastOverflowedUintDowncast(248, value);
          }
          return uint248(value);
      }
  
      /**
       * @dev Returns the downcasted uint240 from uint256, reverting on
       * overflow (when the input is greater than largest uint240).
       *
       * Counterpart to Solidity's `uint240` operator.
       *
       * Requirements:
       *
       * - input must fit into 240 bits
       */
      function toUint240(uint256 value) internal pure returns (uint240) {
          if (value > type(uint240).max) {
              revert SafeCastOverflowedUintDowncast(240, value);
          }
          return uint240(value);
      }
  
      /**
       * @dev Returns the downcasted uint232 from uint256, reverting on
       * overflow (when the input is greater than largest uint232).
       *
       * Counterpart to Solidity's `uint232` operator.
       *
       * Requirements:
       *
       * - input must fit into 232 bits
       */
      function toUint232(uint256 value) internal pure returns (uint232) {
          if (value > type(uint232).max) {
              revert SafeCastOverflowedUintDowncast(232, value);
          }
          return uint232(value);
      }
  
      /**
       * @dev Returns the downcasted uint224 from uint256, reverting on
       * overflow (when the input is greater than largest uint224).
       *
       * Counterpart to Solidity's `uint224` operator.
       *
       * Requirements:
       *
       * - input must fit into 224 bits
       */
      function toUint224(uint256 value) internal pure returns (uint224) {
          if (value > type(uint224).max) {
              revert SafeCastOverflowedUintDowncast(224, value);
          }
          return uint224(value);
      }
  
      /**
       * @dev Returns the downcasted uint216 from uint256, reverting on
       * overflow (when the input is greater than largest uint216).
       *
       * Counterpart to Solidity's `uint216` operator.
       *
       * Requirements:
       *
       * - input must fit into 216 bits
       */
      function toUint216(uint256 value) internal pure returns (uint216) {
          if (value > type(uint216).max) {
              revert SafeCastOverflowedUintDowncast(216, value);
          }
          return uint216(value);
      }
  
      /**
       * @dev Returns the downcasted uint208 from uint256, reverting on
       * overflow (when the input is greater than largest uint208).
       *
       * Counterpart to Solidity's `uint208` operator.
       *
       * Requirements:
       *
       * - input must fit into 208 bits
       */
      function toUint208(uint256 value) internal pure returns (uint208) {
          if (value > type(uint208).max) {
              revert SafeCastOverflowedUintDowncast(208, value);
          }
          return uint208(value);
      }
  
      /**
       * @dev Returns the downcasted uint200 from uint256, reverting on
       * overflow (when the input is greater than largest uint200).
       *
       * Counterpart to Solidity's `uint200` operator.
       *
       * Requirements:
       *
       * - input must fit into 200 bits
       */
      function toUint200(uint256 value) internal pure returns (uint200) {
          if (value > type(uint200).max) {
              revert SafeCastOverflowedUintDowncast(200, value);
          }
          return uint200(value);
      }
  
      /**
       * @dev Returns the downcasted uint192 from uint256, reverting on
       * overflow (when the input is greater than largest uint192).
       *
       * Counterpart to Solidity's `uint192` operator.
       *
       * Requirements:
       *
       * - input must fit into 192 bits
       */
      function toUint192(uint256 value) internal pure returns (uint192) {
          if (value > type(uint192).max) {
              revert SafeCastOverflowedUintDowncast(192, value);
          }
          return uint192(value);
      }
  
      /**
       * @dev Returns the downcasted uint184 from uint256, reverting on
       * overflow (when the input is greater than largest uint184).
       *
       * Counterpart to Solidity's `uint184` operator.
       *
       * Requirements:
       *
       * - input must fit into 184 bits
       */
      function toUint184(uint256 value) internal pure returns (uint184) {
          if (value > type(uint184).max) {
              revert SafeCastOverflowedUintDowncast(184, value);
          }
          return uint184(value);
      }
  
      /**
       * @dev Returns the downcasted uint176 from uint256, reverting on
       * overflow (when the input is greater than largest uint176).
       *
       * Counterpart to Solidity's `uint176` operator.
       *
       * Requirements:
       *
       * - input must fit into 176 bits
       */
      function toUint176(uint256 value) internal pure returns (uint176) {
          if (value > type(uint176).max) {
              revert SafeCastOverflowedUintDowncast(176, value);
          }
          return uint176(value);
      }
  
      /**
       * @dev Returns the downcasted uint168 from uint256, reverting on
       * overflow (when the input is greater than largest uint168).
       *
       * Counterpart to Solidity's `uint168` operator.
       *
       * Requirements:
       *
       * - input must fit into 168 bits
       */
      function toUint168(uint256 value) internal pure returns (uint168) {
          if (value > type(uint168).max) {
              revert SafeCastOverflowedUintDowncast(168, value);
          }
          return uint168(value);
      }
  
      /**
       * @dev Returns the downcasted uint160 from uint256, reverting on
       * overflow (when the input is greater than largest uint160).
       *
       * Counterpart to Solidity's `uint160` operator.
       *
       * Requirements:
       *
       * - input must fit into 160 bits
       */
      function toUint160(uint256 value) internal pure returns (uint160) {
          if (value > type(uint160).max) {
              revert SafeCastOverflowedUintDowncast(160, value);
          }
          return uint160(value);
      }
  
      /**
       * @dev Returns the downcasted uint152 from uint256, reverting on
       * overflow (when the input is greater than largest uint152).
       *
       * Counterpart to Solidity's `uint152` operator.
       *
       * Requirements:
       *
       * - input must fit into 152 bits
       */
      function toUint152(uint256 value) internal pure returns (uint152) {
          if (value > type(uint152).max) {
              revert SafeCastOverflowedUintDowncast(152, value);
          }
          return uint152(value);
      }
  
      /**
       * @dev Returns the downcasted uint144 from uint256, reverting on
       * overflow (when the input is greater than largest uint144).
       *
       * Counterpart to Solidity's `uint144` operator.
       *
       * Requirements:
       *
       * - input must fit into 144 bits
       */
      function toUint144(uint256 value) internal pure returns (uint144) {
          if (value > type(uint144).max) {
              revert SafeCastOverflowedUintDowncast(144, value);
          }
          return uint144(value);
      }
  
      /**
       * @dev Returns the downcasted uint136 from uint256, reverting on
       * overflow (when the input is greater than largest uint136).
       *
       * Counterpart to Solidity's `uint136` operator.
       *
       * Requirements:
       *
       * - input must fit into 136 bits
       */
      function toUint136(uint256 value) internal pure returns (uint136) {
          if (value > type(uint136).max) {
              revert SafeCastOverflowedUintDowncast(136, value);
          }
          return uint136(value);
      }
  
      /**
       * @dev Returns the downcasted uint128 from uint256, reverting on
       * overflow (when the input is greater than largest uint128).
       *
       * Counterpart to Solidity's `uint128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       */
      function toUint128(uint256 value) internal pure returns (uint128) {
          if (value > type(uint128).max) {
              revert SafeCastOverflowedUintDowncast(128, value);
          }
          return uint128(value);
      }
  
      /**
       * @dev Returns the downcasted uint120 from uint256, reverting on
       * overflow (when the input is greater than largest uint120).
       *
       * Counterpart to Solidity's `uint120` operator.
       *
       * Requirements:
       *
       * - input must fit into 120 bits
       */
      function toUint120(uint256 value) internal pure returns (uint120) {
          if (value > type(uint120).max) {
              revert SafeCastOverflowedUintDowncast(120, value);
          }
          return uint120(value);
      }
  
      /**
       * @dev Returns the downcasted uint112 from uint256, reverting on
       * overflow (when the input is greater than largest uint112).
       *
       * Counterpart to Solidity's `uint112` operator.
       *
       * Requirements:
       *
       * - input must fit into 112 bits
       */
      function toUint112(uint256 value) internal pure returns (uint112) {
          if (value > type(uint112).max) {
              revert SafeCastOverflowedUintDowncast(112, value);
          }
          return uint112(value);
      }
  
      /**
       * @dev Returns the downcasted uint104 from uint256, reverting on
       * overflow (when the input is greater than largest uint104).
       *
       * Counterpart to Solidity's `uint104` operator.
       *
       * Requirements:
       *
       * - input must fit into 104 bits
       */
      function toUint104(uint256 value) internal pure returns (uint104) {
          if (value > type(uint104).max) {
              revert SafeCastOverflowedUintDowncast(104, value);
          }
          return uint104(value);
      }
  
      /**
       * @dev Returns the downcasted uint96 from uint256, reverting on
       * overflow (when the input is greater than largest uint96).
       *
       * Counterpart to Solidity's `uint96` operator.
       *
       * Requirements:
       *
       * - input must fit into 96 bits
       */
      function toUint96(uint256 value) internal pure returns (uint96) {
          if (value > type(uint96).max) {
              revert SafeCastOverflowedUintDowncast(96, value);
          }
          return uint96(value);
      }
  
      /**
       * @dev Returns the downcasted uint88 from uint256, reverting on
       * overflow (when the input is greater than largest uint88).
       *
       * Counterpart to Solidity's `uint88` operator.
       *
       * Requirements:
       *
       * - input must fit into 88 bits
       */
      function toUint88(uint256 value) internal pure returns (uint88) {
          if (value > type(uint88).max) {
              revert SafeCastOverflowedUintDowncast(88, value);
          }
          return uint88(value);
      }
  
      /**
       * @dev Returns the downcasted uint80 from uint256, reverting on
       * overflow (when the input is greater than largest uint80).
       *
       * Counterpart to Solidity's `uint80` operator.
       *
       * Requirements:
       *
       * - input must fit into 80 bits
       */
      function toUint80(uint256 value) internal pure returns (uint80) {
          if (value > type(uint80).max) {
              revert SafeCastOverflowedUintDowncast(80, value);
          }
          return uint80(value);
      }
  
      /**
       * @dev Returns the downcasted uint72 from uint256, reverting on
       * overflow (when the input is greater than largest uint72).
       *
       * Counterpart to Solidity's `uint72` operator.
       *
       * Requirements:
       *
       * - input must fit into 72 bits
       */
      function toUint72(uint256 value) internal pure returns (uint72) {
          if (value > type(uint72).max) {
              revert SafeCastOverflowedUintDowncast(72, value);
          }
          return uint72(value);
      }
  
      /**
       * @dev Returns the downcasted uint64 from uint256, reverting on
       * overflow (when the input is greater than largest uint64).
       *
       * Counterpart to Solidity's `uint64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       */
      function toUint64(uint256 value) internal pure returns (uint64) {
          if (value > type(uint64).max) {
              revert SafeCastOverflowedUintDowncast(64, value);
          }
          return uint64(value);
      }
  
      /**
       * @dev Returns the downcasted uint56 from uint256, reverting on
       * overflow (when the input is greater than largest uint56).
       *
       * Counterpart to Solidity's `uint56` operator.
       *
       * Requirements:
       *
       * - input must fit into 56 bits
       */
      function toUint56(uint256 value) internal pure returns (uint56) {
          if (value > type(uint56).max) {
              revert SafeCastOverflowedUintDowncast(56, value);
          }
          return uint56(value);
      }
  
      /**
       * @dev Returns the downcasted uint48 from uint256, reverting on
       * overflow (when the input is greater than largest uint48).
       *
       * Counterpart to Solidity's `uint48` operator.
       *
       * Requirements:
       *
       * - input must fit into 48 bits
       */
      function toUint48(uint256 value) internal pure returns (uint48) {
          if (value > type(uint48).max) {
              revert SafeCastOverflowedUintDowncast(48, value);
          }
          return uint48(value);
      }
  
      /**
       * @dev Returns the downcasted uint40 from uint256, reverting on
       * overflow (when the input is greater than largest uint40).
       *
       * Counterpart to Solidity's `uint40` operator.
       *
       * Requirements:
       *
       * - input must fit into 40 bits
       */
      function toUint40(uint256 value) internal pure returns (uint40) {
          if (value > type(uint40).max) {
              revert SafeCastOverflowedUintDowncast(40, value);
          }
          return uint40(value);
      }
  
      /**
       * @dev Returns the downcasted uint32 from uint256, reverting on
       * overflow (when the input is greater than largest uint32).
       *
       * Counterpart to Solidity's `uint32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       */
      function toUint32(uint256 value) internal pure returns (uint32) {
          if (value > type(uint32).max) {
              revert SafeCastOverflowedUintDowncast(32, value);
          }
          return uint32(value);
      }
  
      /**
       * @dev Returns the downcasted uint24 from uint256, reverting on
       * overflow (when the input is greater than largest uint24).
       *
       * Counterpart to Solidity's `uint24` operator.
       *
       * Requirements:
       *
       * - input must fit into 24 bits
       */
      function toUint24(uint256 value) internal pure returns (uint24) {
          if (value > type(uint24).max) {
              revert SafeCastOverflowedUintDowncast(24, value);
          }
          return uint24(value);
      }
  
      /**
       * @dev Returns the downcasted uint16 from uint256, reverting on
       * overflow (when the input is greater than largest uint16).
       *
       * Counterpart to Solidity's `uint16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       */
      function toUint16(uint256 value) internal pure returns (uint16) {
          if (value > type(uint16).max) {
              revert SafeCastOverflowedUintDowncast(16, value);
          }
          return uint16(value);
      }
  
      /**
       * @dev Returns the downcasted uint8 from uint256, reverting on
       * overflow (when the input is greater than largest uint8).
       *
       * Counterpart to Solidity's `uint8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits
       */
      function toUint8(uint256 value) internal pure returns (uint8) {
          if (value > type(uint8).max) {
              revert SafeCastOverflowedUintDowncast(8, value);
          }
          return uint8(value);
      }
  
      /**
       * @dev Converts a signed int256 into an unsigned uint256.
       *
       * Requirements:
       *
       * - input must be greater than or equal to 0.
       */
      function toUint256(int256 value) internal pure returns (uint256) {
          if (value < 0) {
              revert SafeCastOverflowedIntToUint(value);
          }
          return uint256(value);
      }
  
      /**
       * @dev Returns the downcasted int248 from int256, reverting on
       * overflow (when the input is less than smallest int248 or
       * greater than largest int248).
       *
       * Counterpart to Solidity's `int248` operator.
       *
       * Requirements:
       *
       * - input must fit into 248 bits
       */
      function toInt248(int256 value) internal pure returns (int248 downcasted) {
          downcasted = int248(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(248, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int240 from int256, reverting on
       * overflow (when the input is less than smallest int240 or
       * greater than largest int240).
       *
       * Counterpart to Solidity's `int240` operator.
       *
       * Requirements:
       *
       * - input must fit into 240 bits
       */
      function toInt240(int256 value) internal pure returns (int240 downcasted) {
          downcasted = int240(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(240, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int232 from int256, reverting on
       * overflow (when the input is less than smallest int232 or
       * greater than largest int232).
       *
       * Counterpart to Solidity's `int232` operator.
       *
       * Requirements:
       *
       * - input must fit into 232 bits
       */
      function toInt232(int256 value) internal pure returns (int232 downcasted) {
          downcasted = int232(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(232, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int224 from int256, reverting on
       * overflow (when the input is less than smallest int224 or
       * greater than largest int224).
       *
       * Counterpart to Solidity's `int224` operator.
       *
       * Requirements:
       *
       * - input must fit into 224 bits
       */
      function toInt224(int256 value) internal pure returns (int224 downcasted) {
          downcasted = int224(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(224, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int216 from int256, reverting on
       * overflow (when the input is less than smallest int216 or
       * greater than largest int216).
       *
       * Counterpart to Solidity's `int216` operator.
       *
       * Requirements:
       *
       * - input must fit into 216 bits
       */
      function toInt216(int256 value) internal pure returns (int216 downcasted) {
          downcasted = int216(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(216, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int208 from int256, reverting on
       * overflow (when the input is less than smallest int208 or
       * greater than largest int208).
       *
       * Counterpart to Solidity's `int208` operator.
       *
       * Requirements:
       *
       * - input must fit into 208 bits
       */
      function toInt208(int256 value) internal pure returns (int208 downcasted) {
          downcasted = int208(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(208, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int200 from int256, reverting on
       * overflow (when the input is less than smallest int200 or
       * greater than largest int200).
       *
       * Counterpart to Solidity's `int200` operator.
       *
       * Requirements:
       *
       * - input must fit into 200 bits
       */
      function toInt200(int256 value) internal pure returns (int200 downcasted) {
          downcasted = int200(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(200, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int192 from int256, reverting on
       * overflow (when the input is less than smallest int192 or
       * greater than largest int192).
       *
       * Counterpart to Solidity's `int192` operator.
       *
       * Requirements:
       *
       * - input must fit into 192 bits
       */
      function toInt192(int256 value) internal pure returns (int192 downcasted) {
          downcasted = int192(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(192, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int184 from int256, reverting on
       * overflow (when the input is less than smallest int184 or
       * greater than largest int184).
       *
       * Counterpart to Solidity's `int184` operator.
       *
       * Requirements:
       *
       * - input must fit into 184 bits
       */
      function toInt184(int256 value) internal pure returns (int184 downcasted) {
          downcasted = int184(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(184, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int176 from int256, reverting on
       * overflow (when the input is less than smallest int176 or
       * greater than largest int176).
       *
       * Counterpart to Solidity's `int176` operator.
       *
       * Requirements:
       *
       * - input must fit into 176 bits
       */
      function toInt176(int256 value) internal pure returns (int176 downcasted) {
          downcasted = int176(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(176, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int168 from int256, reverting on
       * overflow (when the input is less than smallest int168 or
       * greater than largest int168).
       *
       * Counterpart to Solidity's `int168` operator.
       *
       * Requirements:
       *
       * - input must fit into 168 bits
       */
      function toInt168(int256 value) internal pure returns (int168 downcasted) {
          downcasted = int168(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(168, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int160 from int256, reverting on
       * overflow (when the input is less than smallest int160 or
       * greater than largest int160).
       *
       * Counterpart to Solidity's `int160` operator.
       *
       * Requirements:
       *
       * - input must fit into 160 bits
       */
      function toInt160(int256 value) internal pure returns (int160 downcasted) {
          downcasted = int160(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(160, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int152 from int256, reverting on
       * overflow (when the input is less than smallest int152 or
       * greater than largest int152).
       *
       * Counterpart to Solidity's `int152` operator.
       *
       * Requirements:
       *
       * - input must fit into 152 bits
       */
      function toInt152(int256 value) internal pure returns (int152 downcasted) {
          downcasted = int152(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(152, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int144 from int256, reverting on
       * overflow (when the input is less than smallest int144 or
       * greater than largest int144).
       *
       * Counterpart to Solidity's `int144` operator.
       *
       * Requirements:
       *
       * - input must fit into 144 bits
       */
      function toInt144(int256 value) internal pure returns (int144 downcasted) {
          downcasted = int144(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(144, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int136 from int256, reverting on
       * overflow (when the input is less than smallest int136 or
       * greater than largest int136).
       *
       * Counterpart to Solidity's `int136` operator.
       *
       * Requirements:
       *
       * - input must fit into 136 bits
       */
      function toInt136(int256 value) internal pure returns (int136 downcasted) {
          downcasted = int136(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(136, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int128 from int256, reverting on
       * overflow (when the input is less than smallest int128 or
       * greater than largest int128).
       *
       * Counterpart to Solidity's `int128` operator.
       *
       * Requirements:
       *
       * - input must fit into 128 bits
       */
      function toInt128(int256 value) internal pure returns (int128 downcasted) {
          downcasted = int128(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(128, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int120 from int256, reverting on
       * overflow (when the input is less than smallest int120 or
       * greater than largest int120).
       *
       * Counterpart to Solidity's `int120` operator.
       *
       * Requirements:
       *
       * - input must fit into 120 bits
       */
      function toInt120(int256 value) internal pure returns (int120 downcasted) {
          downcasted = int120(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(120, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int112 from int256, reverting on
       * overflow (when the input is less than smallest int112 or
       * greater than largest int112).
       *
       * Counterpart to Solidity's `int112` operator.
       *
       * Requirements:
       *
       * - input must fit into 112 bits
       */
      function toInt112(int256 value) internal pure returns (int112 downcasted) {
          downcasted = int112(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(112, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int104 from int256, reverting on
       * overflow (when the input is less than smallest int104 or
       * greater than largest int104).
       *
       * Counterpart to Solidity's `int104` operator.
       *
       * Requirements:
       *
       * - input must fit into 104 bits
       */
      function toInt104(int256 value) internal pure returns (int104 downcasted) {
          downcasted = int104(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(104, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int96 from int256, reverting on
       * overflow (when the input is less than smallest int96 or
       * greater than largest int96).
       *
       * Counterpart to Solidity's `int96` operator.
       *
       * Requirements:
       *
       * - input must fit into 96 bits
       */
      function toInt96(int256 value) internal pure returns (int96 downcasted) {
          downcasted = int96(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(96, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int88 from int256, reverting on
       * overflow (when the input is less than smallest int88 or
       * greater than largest int88).
       *
       * Counterpart to Solidity's `int88` operator.
       *
       * Requirements:
       *
       * - input must fit into 88 bits
       */
      function toInt88(int256 value) internal pure returns (int88 downcasted) {
          downcasted = int88(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(88, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int80 from int256, reverting on
       * overflow (when the input is less than smallest int80 or
       * greater than largest int80).
       *
       * Counterpart to Solidity's `int80` operator.
       *
       * Requirements:
       *
       * - input must fit into 80 bits
       */
      function toInt80(int256 value) internal pure returns (int80 downcasted) {
          downcasted = int80(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(80, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int72 from int256, reverting on
       * overflow (when the input is less than smallest int72 or
       * greater than largest int72).
       *
       * Counterpart to Solidity's `int72` operator.
       *
       * Requirements:
       *
       * - input must fit into 72 bits
       */
      function toInt72(int256 value) internal pure returns (int72 downcasted) {
          downcasted = int72(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(72, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int64 from int256, reverting on
       * overflow (when the input is less than smallest int64 or
       * greater than largest int64).
       *
       * Counterpart to Solidity's `int64` operator.
       *
       * Requirements:
       *
       * - input must fit into 64 bits
       */
      function toInt64(int256 value) internal pure returns (int64 downcasted) {
          downcasted = int64(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(64, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int56 from int256, reverting on
       * overflow (when the input is less than smallest int56 or
       * greater than largest int56).
       *
       * Counterpart to Solidity's `int56` operator.
       *
       * Requirements:
       *
       * - input must fit into 56 bits
       */
      function toInt56(int256 value) internal pure returns (int56 downcasted) {
          downcasted = int56(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(56, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int48 from int256, reverting on
       * overflow (when the input is less than smallest int48 or
       * greater than largest int48).
       *
       * Counterpart to Solidity's `int48` operator.
       *
       * Requirements:
       *
       * - input must fit into 48 bits
       */
      function toInt48(int256 value) internal pure returns (int48 downcasted) {
          downcasted = int48(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(48, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int40 from int256, reverting on
       * overflow (when the input is less than smallest int40 or
       * greater than largest int40).
       *
       * Counterpart to Solidity's `int40` operator.
       *
       * Requirements:
       *
       * - input must fit into 40 bits
       */
      function toInt40(int256 value) internal pure returns (int40 downcasted) {
          downcasted = int40(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(40, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int32 from int256, reverting on
       * overflow (when the input is less than smallest int32 or
       * greater than largest int32).
       *
       * Counterpart to Solidity's `int32` operator.
       *
       * Requirements:
       *
       * - input must fit into 32 bits
       */
      function toInt32(int256 value) internal pure returns (int32 downcasted) {
          downcasted = int32(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(32, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int24 from int256, reverting on
       * overflow (when the input is less than smallest int24 or
       * greater than largest int24).
       *
       * Counterpart to Solidity's `int24` operator.
       *
       * Requirements:
       *
       * - input must fit into 24 bits
       */
      function toInt24(int256 value) internal pure returns (int24 downcasted) {
          downcasted = int24(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(24, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int16 from int256, reverting on
       * overflow (when the input is less than smallest int16 or
       * greater than largest int16).
       *
       * Counterpart to Solidity's `int16` operator.
       *
       * Requirements:
       *
       * - input must fit into 16 bits
       */
      function toInt16(int256 value) internal pure returns (int16 downcasted) {
          downcasted = int16(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(16, value);
          }
      }
  
      /**
       * @dev Returns the downcasted int8 from int256, reverting on
       * overflow (when the input is less than smallest int8 or
       * greater than largest int8).
       *
       * Counterpart to Solidity's `int8` operator.
       *
       * Requirements:
       *
       * - input must fit into 8 bits
       */
      function toInt8(int256 value) internal pure returns (int8 downcasted) {
          downcasted = int8(value);
          if (downcasted != value) {
              revert SafeCastOverflowedIntDowncast(8, value);
          }
      }
  
      /**
       * @dev Converts an unsigned uint256 into a signed int256.
       *
       * Requirements:
       *
       * - input must be less than or equal to maxInt256.
       */
      function toInt256(uint256 value) internal pure returns (int256) {
          // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
          if (value > uint256(type(int256).max)) {
              revert SafeCastOverflowedUintToInt(value);
          }
          return int256(value);
      }
  }
  
  // File: @openzeppelin/contracts/utils/Context.sol
  
  
  // 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;
      }
  }
  
  // File: @openzeppelin/contracts/access/Ownable.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
  
  pragma solidity ^0.8.20;
  
  
  /**
   * @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);
      }
  }
  
  // File: @1inch/solidity-utils/contracts/libraries/AddressArray.sol
  
  
  
  pragma solidity ^0.8.0;
  
  /**
   * @title AddressArray
   * @notice Implements a dynamic array of addresses using a mapping for storage efficiency, with the array length stored at index 0.
   * @dev This library provides basic functionalities such as push, pop, set, and retrieval of addresses in a storage-efficient manner.
   */
  library AddressArray {
      /**
       * @dev Error thrown when attempting to access an index outside the bounds of the array.
       */
      error IndexOutOfBounds();
  
      /**
       * @dev Error thrown when attempting to pop an element from an empty array.
       */
      error PopFromEmptyArray();
  
      /**
       * @dev Error thrown when the output array provided for getting the list of addresses is too small.
       */
      error OutputArrayTooSmall();
  
      uint256 internal constant _ZERO_ADDRESS = 0x8000000000000000000000000000000000000000000000000000000000000000; // Next tx gas optimization
      uint256 internal constant _LENGTH_MASK  = 0x0000000000000000ffffffff0000000000000000000000000000000000000000;
      uint256 internal constant _ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
      uint256 internal constant _ONE_LENGTH   = 0x0000000000000000000000010000000000000000000000000000000000000000;
      uint256 internal constant _LENGTH_OFFSET = 160;
  
      /**
       * @dev Struct containing the raw mapping used to store the addresses and the array length.
       */
      struct Data {
          uint256[1 << 32] _raw;
      }
  
      /**
       * @notice Returns the number of addresses stored in the array.
       * @param self The instance of the Data struct.
       * @return The number of addresses.
       */
      function length(Data storage self) internal view returns (uint256) {
          return (self._raw[0] & _LENGTH_MASK) >> _LENGTH_OFFSET;
      }
  
      /**
       * @notice Retrieves the address at a specified index in the array.
       * @param self The instance of the Data struct.
       * @param i The index to retrieve the address from.
       * @return The address stored at the specified index.
       */
      function at(Data storage self, uint256 i) internal view returns (address) {
          if (i >= 1 << 32) revert IndexOutOfBounds();
          return address(uint160(self._raw[i] & _ADDRESS_MASK));
      }
  
      /**
       * @notice Returns all addresses in the array from storage.
       * @param self The instance of the Data struct.
       * @return output Array containing all the addresses.
       */
      function get(Data storage self) internal view returns (address[] memory output) {
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
              let fst := and(lengthAndFirst, _ADDRESS_MASK)
  
              // Allocate array
              output := mload(0x40)
              mstore(0x40, add(output, mul(0x20, add(1, len))))
              mstore(output, len)
  
              if len {
                  // Copy first element and then the rest in a loop
                  let ptr := add(output, 0x20)
                  mstore(ptr, fst)
                  for { let i := 1 } lt(i, len) { i:= add(i, 1) } {
                      let item := and(sload(add(self.slot, i)), _ADDRESS_MASK)
                      mstore(add(ptr, mul(0x20, i)), item)
                  }
              }
          }
      }
  
      /**
       * @notice Copies the addresses into the provided output array.
       * @param self The instance of the Data struct.
       * @param input The array to copy the addresses into.
       * @return output The provided output array filled with addresses.
       */
      function get(Data storage self, address[] memory input) internal view returns (address[] memory output) {
          output = input;
          bytes4 err = OutputArrayTooSmall.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
              let fst := and(lengthAndFirst, _ADDRESS_MASK)
  
              if gt(len, mload(input)) {
                  mstore(0, err)
                  revert(0, 4)
              }
              if len {
                  // Copy first element and then the rest in a loop
                  let ptr := add(output, 0x20)
                  mstore(ptr, fst)
                  for { let i := 1 } lt(i, len) { i:= add(i, 1) } {
                      let item := and(sload(add(self.slot, i)), _ADDRESS_MASK)
                      mstore(add(ptr, mul(0x20, i)), item)
                  }
              }
          }
      }
  
      /**
       * @notice Adds an address to the end of the array.
       * @param self The instance of the Data struct.
       * @param account The address to add.
       * @return res The new length of the array.
       */
      function push(Data storage self, address account) internal returns (uint256 res) {
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
  
              switch len
              case 0 {
                  sstore(self.slot, or(account, _ONE_LENGTH))
              }
              default {
                  sstore(self.slot, add(lengthAndFirst, _ONE_LENGTH))
                  sstore(add(self.slot, len), or(account, _ZERO_ADDRESS))
              }
              res := add(len, 1)
          }
      }
  
      /**
       * @notice Removes the last address from the array.
       * @param self The instance of the Data struct.
       */
      function pop(Data storage self) internal {
          bytes4 err = PopFromEmptyArray.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
  
              switch len
              case 0 {
                  mstore(0, err)
                  revert(0, 4)
              }
              case 1 {
                  sstore(self.slot, _ZERO_ADDRESS)
              }
              default {
                  sstore(self.slot, sub(lengthAndFirst, _ONE_LENGTH))
              }
          }
      }
  
      /**
       * @notice Array pop back operation for storage `self` that returns popped element.
       * @param self The instance of the Data struct.
       * @return res The address that was removed from the array.
       */
      function popGet(Data storage self) internal returns(address res) {
          bytes4 err = PopFromEmptyArray.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
  
              switch len
              case 0 {
                  mstore(0, err)
                  revert(0, 4)
              }
              case 1 {
                  res := and(lengthAndFirst, _ADDRESS_MASK)
                  sstore(self.slot, _ZERO_ADDRESS)
              }
              default {
                  res := and(sload(add(self.slot, sub(len, 1))), _ADDRESS_MASK)
                  sstore(self.slot, sub(lengthAndFirst, _ONE_LENGTH))
              }
          }
      }
  
      /**
       * @notice Sets the address at a specified index in the array.
       * @param self The instance of the Data struct.
       * @param index The index at which to set the address.
       * @param account The address to set at the specified index.
       */
      function set(Data storage self, uint256 index, address account) internal {
          bytes4 err = IndexOutOfBounds.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let lengthAndFirst := sload(self.slot)
              let len := shr(_LENGTH_OFFSET, and(lengthAndFirst, _LENGTH_MASK))
              let fst := and(lengthAndFirst, _ADDRESS_MASK)
  
              if iszero(lt(index, len)) {
                  mstore(0, err)
                  revert(0, 4)
              }
  
              switch index
              case 0 {
                  sstore(self.slot, or(xor(lengthAndFirst, fst), account))
              }
              default {
                  sstore(add(self.slot, index), or(account, _ZERO_ADDRESS))
              }
          }
      }
  
      /**
       * @notice Erase length of the array.
       * @param self The instance of the Data struct.
       */
      function erase(Data storage self) internal {
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              sstore(self.slot, _ADDRESS_MASK)
          }
      }
  }
  
  // File: @1inch/solidity-utils/contracts/libraries/AddressSet.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  /**
   * @title AddressSet
   * @notice Library for managing sets of addresses, allowing operations such as add, remove, and contains.
   * Utilizes the AddressArray library for underlying data storage.
   */
  library AddressSet {
      using AddressArray for AddressArray.Data;
  
      uint256 internal constant _NULL_INDEX = type(uint256).max;
  
      /**
       * @dev Data struct from AddressArray.Data items
       * and lookup mapping address => index in data array.
       */
      struct Data {
          AddressArray.Data items;
          mapping(address => uint256) lookup;
      }
  
      /**
       * @notice Determines the number of addresses in the set.
       * @param s The set of addresses.
       * @return The number of addresses in the set.
       */
      function length(Data storage s) internal view returns (uint256) {
          return s.items.length();
      }
  
      /**
       * @notice Retrieves the address at a specified index in the set.
       * @param s The set of addresses.
       * @param index The index of the address to retrieve.
       * @return The address at the specified index.
       */
      function at(Data storage s, uint256 index) internal view returns (address) {
          return s.items.at(index);
      }
  
      /**
       * @notice Checks if the set contains the specified address.
       * @param s The set of addresses.
       * @param item The address to check for.
       * @return True if the set contains the address, false otherwise.
       */
      function contains(Data storage s, address item) internal view returns (bool) {
          uint256 index = s.lookup[item];
          return index != 0 && index != _NULL_INDEX;
      }
  
      /**
       * @notice Returns list of addresses from storage `s`.
       * @param s The set of addresses.
       * @return The array of addresses stored in `s`.
       */
      function get(Data storage s) internal view returns (address[] memory) {
          return s.items.get();
      }
  
      /**
       * @notice Puts list of addresses from `s` storage into `output` array.
       * @param s The set of addresses.
       * @return The provided output array filled with addresses.
       */
      function get(Data storage s, address[] memory input) internal view returns (address[] memory) {
          return s.items.get(input);
      }
  
      /**
       * @notice Adds an address to the set if it is not already present.
       * @param s The set of addresses.
       * @param item The address to add.
       * @return True if the address was added to the set, false if it was already present.
       */
      function add(Data storage s, address item) internal returns (bool) {
          uint256 index = s.lookup[item];
          if (index != 0 && index != _NULL_INDEX) {
              return false;
          }
          s.lookup[item] = s.items.push(item);
          return true;
      }
  
      /**
       * @notice Removes an address from the set if it exists.
       * @param s The set of addresses.
       * @param item The address to remove.
       * @return True if the address was removed from the set, false if it was not found.
       */
      function remove(Data storage s, address item) internal returns (bool) {
          uint256 index = s.lookup[item];
          s.lookup[item] = _NULL_INDEX;
          if (index == 0 || index == _NULL_INDEX) {
              return false;
          }
  
          address lastItem = s.items.popGet();
          if (lastItem != item) {
              unchecked {
                  s.items.set(index - 1, lastItem);
                  s.lookup[lastItem] = index;
              }
          }
          return true;
      }
  
      /**
       * @notice Erases set from storage `s`.
       * @param s The set of addresses.
       * @return items All removed items.
       */
      function erase(Data storage s) internal returns(address[] memory items) {
          items = s.items.get();
          uint256 len = items.length;
          if (len > 0) {
              s.items.erase();
              unchecked {
                  for (uint256 i = 0; i < len; i++) {
                      s.lookup[items[i]] = _NULL_INDEX;
                  }
              }
          }
      }
  }
  
  // File: @1inch/solidity-utils/contracts/libraries/AddressLib.sol
  
  
  
  pragma solidity ^0.8.0;
  
  type Address is uint256;
  
  /**
  * @notice AddressLib
  * @notice Library for working with addresses encoded as uint256 values, which can include flags in the highest bits.
  */
  library AddressLib {
      uint256 private constant _LOW_160_BIT_MASK = (1 << 160) - 1;
  
      /**
      * @notice Returns the address representation of a uint256.
      * @param a The uint256 value to convert to an address.
      * @return The address representation of the provided uint256 value.
      */
      function get(Address a) internal pure returns (address) {
          return address(uint160(Address.unwrap(a) & _LOW_160_BIT_MASK));
      }
  
      /**
      * @notice Checks if a given flag is set for the provided address.
      * @param a The address to check for the flag.
      * @param flag The flag to check for in the provided address.
      * @return True if the provided flag is set in the address, false otherwise.
      */
      function getFlag(Address a, uint256 flag) internal pure returns (bool) {
          return (Address.unwrap(a) & flag) != 0;
      }
  
      /**
      * @notice Returns a uint32 value stored at a specific bit offset in the provided address.
      * @param a The address containing the uint32 value.
      * @param offset The bit offset at which the uint32 value is stored.
      * @return The uint32 value stored in the address at the specified bit offset.
      */
      function getUint32(Address a, uint256 offset) internal pure returns (uint32) {
          return uint32(Address.unwrap(a) >> offset);
      }
  
      /**
      * @notice Returns a uint64 value stored at a specific bit offset in the provided address.
      * @param a The address containing the uint64 value.
      * @param offset The bit offset at which the uint64 value is stored.
      * @return The uint64 value stored in the address at the specified bit offset.
      */
      function getUint64(Address a, uint256 offset) internal pure returns (uint64) {
          return uint64(Address.unwrap(a) >> offset);
      }
  }
  
  // File: @1inch/solidity-utils/contracts/libraries/RevertReasonForwarder.sol
  
  
  
  pragma solidity ^0.8.0;
  
  /**
   * @title RevertReasonForwarder
   * @notice Provides utilities for forwarding and retrieving revert reasons from failed external calls.
   */
  library RevertReasonForwarder {
      /**
       * @dev Forwards the revert reason from the latest external call.
       * This method allows propagating the revert reason of a failed external call to the caller.
       */
      function reRevert() internal pure {
          // bubble up revert reason from latest external call
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let ptr := mload(0x40)
              returndatacopy(ptr, 0, returndatasize())
              revert(ptr, returndatasize())
          }
      }
  
      /**
       * @dev Retrieves the revert reason from the latest external call.
       * This method enables capturing the revert reason of a failed external call for inspection or processing.
       * @return reason The latest external call revert reason.
       */
      function reReason() internal pure returns (bytes memory reason) {
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              reason := mload(0x40)
              let length := returndatasize()
              mstore(reason, length)
              returndatacopy(add(reason, 0x20), 0, length)
              mstore(0x40, add(reason, add(0x20, length)))
          }
      }
  }
  
  // File: @1inch/solidity-utils/contracts/interfaces/IERC7597Permit.sol
  
  
  
  pragma solidity ^0.8.0;
  
  interface IERC7597Permit {
      function permit(
          address owner,
          address spender,
          uint256 value,
          uint256 deadline,
          bytes memory signature
      ) external;
  }
  
  // File: @1inch/solidity-utils/contracts/interfaces/IPermit2.sol
  
  
  
  pragma solidity ^0.8.0;
  
  /**
   * @title IPermit2
   * @dev Interface for a flexible permit system that extends ERC20 tokens to support permits in tokens lacking native permit functionality.
   */
  interface IPermit2 {
      /**
       * @dev Struct for holding permit details.
       * @param token ERC20 token address for which the permit is issued.
       * @param amount The maximum amount allowed to spend.
       * @param expiration Timestamp until which the permit is valid.
       * @param nonce An incrementing value for each signature, unique per owner, token, and spender.
       */
      struct PermitDetails {
          address token;
          uint160 amount;
          uint48 expiration;
          uint48 nonce;
      }
  
      /**
       * @dev Struct for a single token allowance permit.
       * @param details Permit details including token, amount, expiration, and nonce.
       * @param spender Address authorized to spend the tokens.
       * @param sigDeadline Deadline for the permit signature, ensuring timeliness of the permit.
       */
      struct PermitSingle {
          PermitDetails details;
          address spender;
          uint256 sigDeadline;
      }
  
      /**
       * @dev Struct for packed allowance data to optimize storage.
       * @param amount Amount allowed.
       * @param expiration Permission expiry timestamp.
       * @param nonce Unique incrementing value for tracking allowances.
       */
      struct PackedAllowance {
          uint160 amount;
          uint48 expiration;
          uint48 nonce;
      }
  
      /**
       * @notice Executes a token transfer from one address to another.
       * @param user The token owner's address.
       * @param spender The address authorized to spend the tokens.
       * @param amount The amount of tokens to transfer.
       * @param token The address of the token being transferred.
       */
      function transferFrom(address user, address spender, uint160 amount, address token) external;
  
      /**
       * @notice Issues a permit for spending tokens via a signed authorization.
       * @param owner The token owner's address.
       * @param permitSingle Struct containing the permit details.
       * @param signature The signature proving the owner authorized the permit.
       */
      function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
  
      /**
       * @notice Retrieves the allowance details between a token owner and spender.
       * @param user The token owner's address.
       * @param token The token address.
       * @param spender The spender's address.
       * @return The packed allowance details.
       */
      function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
  }
  
  // File: @1inch/solidity-utils/contracts/interfaces/IDaiLikePermit.sol
  
  
  
  pragma solidity ^0.8.0;
  
  /**
   * @title IDaiLikePermit
   * @dev Interface for Dai-like permit function allowing token spending via signatures.
   */
  interface IDaiLikePermit {
      /**
       * @notice Approves spending of tokens via off-chain signatures.
       * @param holder Token holder's address.
       * @param spender Spender's address.
       * @param nonce Current nonce of the holder.
       * @param expiry Time when the permit expires.
       * @param allowed True to allow, false to disallow spending.
       * @param v, r, s Signature components.
       */
      function permit(
          address holder,
          address spender,
          uint256 nonce,
          uint256 expiry,
          bool allowed,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external;
  }
  
  // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
  
  pragma solidity ^0.8.20;
  
  /**
   * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
   * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
   *
   * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
   * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
   * need to send a transaction, and thus is not required to hold Ether at all.
   *
   * ==== Security Considerations
   *
   * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
   * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
   * considered as an intention to spend the allowance in any specific way. The second is that because permits have
   * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
   * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
   * generally recommended is:
   *
   * ```solidity
   * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
   *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
   *     doThing(..., value);
   * }
   *
   * function doThing(..., uint256 value) public {
   *     token.safeTransferFrom(msg.sender, address(this), value);
   *     ...
   * }
   * ```
   *
   * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
   * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
   * {SafeERC20-safeTransferFrom}).
   *
   * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
   * contracts should have entry points that don't rely on permit.
   */
  interface IERC20Permit {
      /**
       * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
       * given ``owner``'s signed approval.
       *
       * IMPORTANT: The same issues {IERC20-approve} has related to transaction
       * ordering also apply here.
       *
       * Emits an {Approval} event.
       *
       * Requirements:
       *
       * - `spender` cannot be the zero address.
       * - `deadline` must be a timestamp in the future.
       * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
       * over the EIP712-formatted function arguments.
       * - the signature must use ``owner``'s current nonce (see {nonces}).
       *
       * For more information on the signature format, see the
       * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
       * section].
       *
       * CAUTION: See Security Considerations above.
       */
      function permit(
          address owner,
          address spender,
          uint256 value,
          uint256 deadline,
          uint8 v,
          bytes32 r,
          bytes32 s
      ) external;
  
      /**
       * @dev Returns the current nonce for `owner`. This value must be
       * included whenever a signature is generated for {permit}.
       *
       * Every successful call to {permit} increases ``owner``'s nonce by one. This
       * prevents a signature from being used multiple times.
       */
      function nonces(address owner) external view returns (uint256);
  
      /**
       * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
       */
      // solhint-disable-next-line func-name-mixedcase
      function DOMAIN_SEPARATOR() external view returns (bytes32);
  }
  
  // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
  
  
  // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
  
  pragma solidity ^0.8.20;
  
  /**
   * @dev Interface of the ERC20 standard as defined in the EIP.
   */
  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);
  }
  
  // File: @1inch/solidity-utils/contracts/interfaces/IWETH.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  /**
   * @title IWETH
   * @dev Interface for wrapper as WETH-like token.
   */
  interface IWETH is IERC20 {
      /**
       * @notice Emitted when Ether is deposited to get wrapper tokens.
       */
      event Deposit(address indexed dst, uint256 wad);
  
      /**
       * @notice Emitted when wrapper tokens is withdrawn as Ether.
       */
      event Withdrawal(address indexed src, uint256 wad);
  
      /**
       * @notice Deposit Ether to get wrapper tokens.
       */
      function deposit() external payable;
  
      /**
       * @notice Withdraw wrapped tokens as Ether.
       * @param amount Amount of wrapped tokens to withdraw.
       */
      function withdraw(uint256 amount) external;
  }
  
  // File: @1inch/solidity-utils/contracts/libraries/SafeERC20.sol
  
  
  
  pragma solidity ^0.8.0;
  
  
  
  
  
  
  
  
  /**
   * @title Implements efficient safe methods for ERC20 interface.
   * @notice Compared to the standard ERC20, this implementation offers several enhancements:
   * 1. more gas-efficient, providing significant savings in transaction costs.
   * 2. support for different permit implementations
   * 3. forceApprove functionality
   * 4. support for WETH deposit and withdraw
   */
  library SafeERC20 {
      error SafeTransferFailed();
      error SafeTransferFromFailed();
      error ForceApproveFailed();
      error SafeIncreaseAllowanceFailed();
      error SafeDecreaseAllowanceFailed();
      error SafePermitBadLength();
      error Permit2TransferAmountTooHigh();
  
      // Uniswap Permit2 address
      address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
      bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857;  // SafePermitBadLength.selector
      uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
  
      /**
       * @notice Fetches the balance of a specific ERC20 token held by an account.
       * Consumes less gas then regular `ERC20.balanceOf`.
       * @dev Note that the implementation does not perform dirty bits cleaning, so it is the
       * responsibility of the caller to make sure that the higher 96 bits of the `account` parameter are clean.
       * @param token The IERC20 token contract for which the balance will be fetched.
       * @param account The address of the account whose token balance will be fetched.
       * @return tokenBalance The balance of the specified ERC20 token held by the account.
       */
      function safeBalanceOf(
          IERC20 token,
          address account
      ) internal view returns(uint256 tokenBalance) {
          bytes4 selector = IERC20.balanceOf.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              mstore(0x00, selector)
              mstore(0x04, account)
              let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
              tokenBalance := mload(0)
  
              if or(iszero(success), lt(returndatasize(), 0x20)) {
                  let ptr := mload(0x40)
                  returndatacopy(ptr, 0, returndatasize())
                  revert(ptr, returndatasize())
              }
          }
      }
  
      /**
       * @notice Attempts to safely transfer tokens from one address to another.
       * @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom.
       * Either requires `true` in return data, or requires target to be smart-contract and empty return data.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
       * @param token The IERC20 token contract from which the tokens will be transferred.
       * @param from The address from which the tokens will be transferred.
       * @param to The address to which the tokens will be transferred.
       * @param amount The amount of tokens to transfer.
       * @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom.
       */
      function safeTransferFromUniversal(
          IERC20 token,
          address from,
          address to,
          uint256 amount,
          bool permit2
      ) internal {
          if (permit2) {
              safeTransferFromPermit2(token, from, to, amount);
          } else {
              safeTransferFrom(token, from, to, amount);
          }
      }
  
      /**
       * @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard.
       * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
       * @param token The IERC20 token contract from which the tokens will be transferred.
       * @param from The address from which the tokens will be transferred.
       * @param to The address to which the tokens will be transferred.
       * @param amount The amount of tokens to transfer.
       */
      function safeTransferFrom(
          IERC20 token,
          address from,
          address to,
          uint256 amount
      ) internal {
          bytes4 selector = token.transferFrom.selector;
          bool success;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let data := mload(0x40)
  
              mstore(data, selector)
              mstore(add(data, 0x04), from)
              mstore(add(data, 0x24), to)
              mstore(add(data, 0x44), amount)
              success := call(gas(), token, 0, data, 100, 0x0, 0x20)
              if success {
                  switch returndatasize()
                  case 0 {
                      success := gt(extcodesize(token), 0)
                  }
                  default {
                      success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                  }
              }
          }
          if (!success) revert SafeTransferFromFailed();
      }
  
      /**
       * @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard.
       * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
       * @param token The IERC20 token contract from which the tokens will be transferred.
       * @param from The address from which the tokens will be transferred.
       * @param to The address to which the tokens will be transferred.
       * @param amount The amount of tokens to transfer.
       */
      function safeTransferFromPermit2(
          IERC20 token,
          address from,
          address to,
          uint256 amount
      ) internal {
          if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
          bytes4 selector = IPermit2.transferFrom.selector;
          bool success;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let data := mload(0x40)
  
              mstore(data, selector)
              mstore(add(data, 0x04), from)
              mstore(add(data, 0x24), to)
              mstore(add(data, 0x44), amount)
              mstore(add(data, 0x64), token)
              success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
              if success {
                  success := gt(extcodesize(_PERMIT2), 0)
              }
          }
          if (!success) revert SafeTransferFromFailed();
      }
  
      /**
       * @notice Attempts to safely transfer tokens to another address.
       * @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `to` parameter are clean.
       * @param token The IERC20 token contract from which the tokens will be transferred.
       * @param to The address to which the tokens will be transferred.
       * @param value The amount of tokens to transfer.
       */
      function safeTransfer(
          IERC20 token,
          address to,
          uint256 value
      ) internal {
          if (!_makeCall(token, token.transfer.selector, to, value)) {
              revert SafeTransferFailed();
          }
      }
  
      /**
       * @notice Attempts to approve a spender to spend a certain amount of tokens.
       * @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
       * @param token The IERC20 token contract on which the call will be made.
       * @param spender The address which will spend the funds.
       * @param value The amount of tokens to be spent.
       */
      function forceApprove(
          IERC20 token,
          address spender,
          uint256 value
      ) internal {
          if (!_makeCall(token, token.approve.selector, spender, value)) {
              if (
                  !_makeCall(token, token.approve.selector, spender, 0) ||
                  !_makeCall(token, token.approve.selector, spender, value)
              ) {
                  revert ForceApproveFailed();
              }
          }
      }
  
      /**
       * @notice Safely increases the allowance of a spender.
       * @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction.
       * Then uses `forceApprove` to increase the allowance.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
       * @param token The IERC20 token contract on which the call will be made.
       * @param spender The address which will spend the funds.
       * @param value The amount of tokens to increase the allowance by.
       */
      function safeIncreaseAllowance(
          IERC20 token,
          address spender,
          uint256 value
      ) internal {
          uint256 allowance = token.allowance(address(this), spender);
          if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
          forceApprove(token, spender, allowance + value);
      }
  
      /**
       * @notice Safely decreases the allowance of a spender.
       * @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction.
       * Then uses `forceApprove` to increase the allowance.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
       * @param token The IERC20 token contract on which the call will be made.
       * @param spender The address which will spend the funds.
       * @param value The amount of tokens to decrease the allowance by.
       */
      function safeDecreaseAllowance(
          IERC20 token,
          address spender,
          uint256 value
      ) internal {
          uint256 allowance = token.allowance(address(this), spender);
          if (value > allowance) revert SafeDecreaseAllowanceFailed();
          forceApprove(token, spender, allowance - value);
      }
  
      /**
       * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
       * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
       * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
       * @param token The IERC20 token to execute the permit function on.
       * @param permit The permit data to be used in the function call.
       */
      function safePermit(IERC20 token, bytes calldata permit) internal {
          if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
      }
  
      /**
       * @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters.
       * Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
       * @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
       * @param token The IERC20 token to execute the permit function on.
       * @param owner The owner of the tokens for which the permit is made.
       * @param spender The spender allowed to spend the tokens by the permit.
       * @param permit The permit data to be used in the function call.
       */
      function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
          if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
      }
  
      /**
       * @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
       * @dev Invokes `tryPermit` with sender as owner and contract as spender.
       * @param token The IERC20 token to execute the permit function on.
       * @param permit The permit data to be used in the function call.
       * @return success Returns true if the permit function was successfully executed, false otherwise.
       */
      function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
          return tryPermit(token, msg.sender, address(this), permit);
      }
  
      /**
       * @notice The function attempts to call the permit function on a given ERC20 token.
       * @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, and IPermit2.
       * It accommodates both Compact and Full formats of these permit types.
       * Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter
       * for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
       * gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and
       * zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
       * before invocation for optimized performance.
       * Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
       * the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
       * @param token The address of the ERC20 token on which to call the permit function.
       * @param owner The owner of the tokens. This address should have signed the off-chain permit.
       * @param spender The address which will be approved for transfer of tokens.
       * @param permit The off-chain permit data, containing different fields depending on the type of permit function.
       * @return success A boolean indicating whether the permit call was successful.
       */
      function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
          // load function selectors for different permit standards
          bytes4 permitSelector = IERC20Permit.permit.selector;
          bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
          bytes4 permit2Selector = IPermit2.permit.selector;
          bytes4 erc7597PermitSelector = IERC7597Permit.permit.selector;
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let ptr := mload(0x40)
  
              // Switch case for different permit lengths, indicating different permit standards
              switch permit.length
              // Compact IERC20Permit
              case 100 {
                  mstore(ptr, permitSelector)     // store selector
                  mstore(add(ptr, 0x04), owner)   // store owner
                  mstore(add(ptr, 0x24), spender) // store spender
  
                  // Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
                  {  // stack too deep
                      let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
                      let vs := calldataload(add(permit.offset, 0x44))                 // loads permit.offset 0x44..0x63
  
                      calldatacopy(add(ptr, 0x44), permit.offset, 0x20)            // store value     = copy permit.offset 0x00..0x19
                      mstore(add(ptr, 0x64), sub(deadline, 1))                     // store deadline  = deadline - 1
                      mstore(add(ptr, 0x84), add(27, shr(255, vs)))                // store v         = most significant bit of vs + 27 (27 or 28)
                      calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r         = copy permit.offset 0x24..0x43
                      mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))                   // store s         = vs without most significant bit
                  }
                  // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                  success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
              }
              // Compact IDaiLikePermit
              case 72 {
                  mstore(ptr, daiPermitSelector)  // store selector
                  mstore(add(ptr, 0x04), owner)   // store owner
                  mstore(add(ptr, 0x24), spender) // store spender
  
                  // Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
                  {  // stack too deep
                      let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
                      let vs := calldataload(add(permit.offset, 0x28))               // loads permit.offset 0x28..0x47
  
                      mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce   = copy permit.offset 0x00..0x03
                      mstore(add(ptr, 0x64), sub(expiry, 1))                        // store expiry  = expiry - 1
                      mstore(add(ptr, 0x84), true)                                  // store allowed = true
                      mstore(add(ptr, 0xa4), add(27, shr(255, vs)))                 // store v       = most significant bit of vs + 27 (27 or 28)
                      calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)  // store r       = copy permit.offset 0x08..0x27
                      mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))                    // store s       = vs without most significant bit
                  }
                  // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                  success := call(gas(), token, 0, ptr, 0x104, 0, 0)
              }
              // IERC20Permit
              case 224 {
                  mstore(ptr, permitSelector)
                  calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                  // IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
                  success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
              }
              // IDaiLikePermit
              case 256 {
                  mstore(ptr, daiPermitSelector)
                  calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                  // IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
                  success := call(gas(), token, 0, ptr, 0x104, 0, 0)
              }
              // Compact IPermit2
              case 96 {
                  // Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
                  mstore(ptr, permit2Selector)  // store selector
                  mstore(add(ptr, 0x04), owner) // store owner
                  mstore(add(ptr, 0x24), token) // store token
  
                  calldatacopy(add(ptr, 0x50), permit.offset, 0x14)             // store amount = copy permit.offset 0x00..0x13
                  // and(0xffffffffffff, ...) - conversion to uint48
                  mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
                  mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
                  mstore(add(ptr, 0xa4), spender)                               // store spender
                  // and(0xffffffffffff, ...) - conversion to uint48
                  mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
                  mstore(add(ptr, 0xe4), 0x100)                                 // store offset = 256
                  mstore(add(ptr, 0x104), 0x40)                                 // store length = 64
                  calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r      = copy permit.offset 0x20..0x3f
                  calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs     = copy permit.offset 0x40..0x5f
                  // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                  success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
              }
              // IPermit2
              case 352 {
                  mstore(ptr, permit2Selector)
                  calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                  // IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
                  success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
              }
              // Dynamic length
              default {
                  mstore(ptr, erc7597PermitSelector)
                  calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
                  // IERC7597Permit.permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature)
                  success := call(gas(), token, 0, ptr, add(permit.length, 4), 0, 0)
              }
          }
      }
  
      /**
       * @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns.
       * @param token The IERC20 token contract on which the call will be made.
       * @param selector The function signature that is to be called on the token contract.
       * @param to The address to which the token amount will be transferred.
       * @param amount The token amount to be transferred.
       * @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure.
       * In case of success but no returned data, validates that the contract code exists.
       * In case of returned data, ensures that it's a boolean `true`.
       */
      function _makeCall(
          IERC20 token,
          bytes4 selector,
          address to,
          uint256 amount
      ) private returns (bool success) {
          assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
              let data := mload(0x40)
  
              mstore(data, selector)
              mstore(add(data, 0x04), to)
              mstore(add(data, 0x24), amount)
              success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
              if success {
                  switch returndatasize()
                  case 0 {
                      success := gt(extcodesize(token), 0)
                  }
                  default {
                      success := and(gt(returndatasize(), 31), eq(mload(0), 1))
                  }
              }
          }
      }
  
      /**
       * @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`.
       * @param weth The IWETH token contract.
       * @param amount The amount of Ether to deposit into the IWETH contract.
       */
      function safeDeposit(IWETH weth, uint256 amount) internal {
          if (amount > 0) {
              bytes4 selector = IWETH.deposit.selector;
              assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
                  mstore(0, selector)
                  if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
                      let ptr := mload(0x40)
                      returndatacopy(ptr, 0, returndatasize())
                      revert(ptr, returndatasize())
                  }
              }
          }
      }
  
      /**
       * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`.
       * @dev Uses inline assembly to interact with the IWETH contract.
       * @param weth The IWETH token contract.
       * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
       */
      function safeWithdraw(IWETH weth, uint256 amount) internal {
          bytes4 selector = IWETH.withdraw.selector;
          assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
              mstore(0, selector)
              mstore(4, amount)
              if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
                  let ptr := mload(0x40)
                  returndatacopy(ptr, 0, returndatasize())
                  revert(ptr, returndatasize())
              }
          }
      }
  
      /**
       * @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient.
       * Consumes less gas then regular `IWETH.withdraw`.
       * @param weth The IWETH token contract.
       * @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
       * @param to The recipient of the withdrawn Ether.
       */
      function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
          safeWithdraw(weth, amount);
          if (to != address(this)) {
              assembly ("memory-safe") {  // solhint-disable-line no-inline-assembly
                  if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
                      let ptr := mload(0x40)
                      returndatacopy(ptr, 0, returndatasize())
                      revert(ptr, returndatasize())
                  }
              }
          }
      }
  }
  
  // File: .deps/incentives-pool/contracts/interface/IWETH9.sol
  
  pragma solidity >=0.7.0 <0.9.0;
  
  // See https://github.com/gnosis/canonical-weth/tree/master
  interface IWETH9 {
      function withdraw(uint256 value) external;
  }
  
  // File: .deps/incentives-pool/contracts/interface/ICurvePlainPool.sol
  
  pragma solidity >=0.7.0 <0.9.0;
  
  // See https://docs.curve.fi/stableswap-exchange/stableswap/pools/plain_pools/#exchange
  interface ICurvePlainPool {
      function coins(uint256 i) external view returns (address);
      function exchange(
          int128 i,
          int128 j,
          uint256 dx,
          uint256 min_dy
      ) external payable returns (uint256);
  }
  
  // File: .deps/incentives-pool/contracts/IncentivesPool.sol
  
  
  
  pragma solidity >=0.7.0 <0.9.0;
  
  
  
  
  
  
  
  
  
  /// @notice Incentives pool to improve quote execution on a DEX for specific buy token.
  ///         Requires target DEX pool to be CurvePlainPool-like.
  contract IncentivesPool is Ownable {
  
  
      // Errors
  
      error OnlyOwner();
      error OnlyManager();
      error OnlySettlements();
      error OnlySolvers();
      error SettlementAlreadyAdded();
      error SolverAlreadyAdded();
      error OwnerCannotRescueFeeToken();
      error BuyTokenIncorrect(address sellToken);
  
  
      // Events
  
      event ManagerUpdated(address indexed addr);
      event SettlementsUpdated(address indexed addr, bool added);
      event SolversUpdated(address indexed addr, bool added);
      event OrderExecuted(uint256 netDy, uint256 solverFee);
  
  
      // Libraries
  
      // using TokensAndAmounts for bytes;
      using SafeERC20 for IERC20;
      using AddressLib for Address;
      using AddressSet for AddressSet.Data;
  
  
      // Attributes
  
      // Constants
      address private constant ETH_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
      address private constant WETH_TOKEN = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
      IWETH9 private constant WETH9 = IWETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
      ICurvePlainPool public immutable _targetPool; // Assumes pool is CurvePlainPool-like
      IERC20 public immutable _buyToken; // Also token for solver fees
  
      // Owner-controlled
      address public _manager;
      AddressSet.Data private _settlements;
  
      // Manager-controlled
      AddressSet.Data private _solvers;
  
  
      // Modifiers
  
      modifier onlyManager {
          if (msg.sender != _manager) revert OnlyManager();
          _;
      }
  
      modifier onlySolvers {
          if (!_solvers.contains(tx.origin)) revert OnlySolvers();
          _;
      }
  
  
      // Constructor
  
      constructor(
          address owner,
          address manager,
          address settlement,
          address solver,
          address targetPool,
          address buyToken
      ) Ownable(owner) {
          _manager = manager;
  
          _targetPool = ICurvePlainPool(targetPool);
          _buyToken = IERC20(buyToken);
  
          if (settlement != address(0)) {
              _addSettlement(settlement);
          }
          if (solver != address(0)) {
              _addSolver(solver);
          }
      }
  
  
      // Functions: management
  
      function setManager(address manager) public onlyOwner {
          _manager = manager;
          emit ManagerUpdated(manager);
      }
  
      function addSettlement(address settlement) external onlyOwner {
          _addSettlement(settlement);
      }
  
      function removeSettlement(address settlement) external onlyOwner {
          if (_settlements.remove(settlement)) emit SettlementsUpdated(settlement, false);
      }
  
      function addSolver(address solver) external onlyManager {
          _addSolver(solver);
      }
  
      function removeSolver(address solver) external onlyManager {
          if (_solvers.remove(solver)) emit SolversUpdated(solver, false);
      }
  
      function isSettlement(address settlement) external view returns (bool) {
          return _settlements.contains(settlement);
      }
  
      function isSolver(address solver) external view returns (bool) {
          return _solvers.contains(solver);
      }
  
      function _addSettlement(address settlement) internal {
          if (!_settlements.add(settlement)) revert SettlementAlreadyAdded();
          emit SettlementsUpdated(settlement, true);
      }
  
      function _addSolver(address solver) internal {
          if (!_solvers.add(solver)) revert SolverAlreadyAdded();
          emit SolversUpdated(solver, true);
      }
  
  
      // Functions: funding
  
      receive() external payable {}
  
      function rescueFunds(IERC20 token) external onlyOwner {
          if (address(token) == address(_buyToken)) revert OwnerCannotRescueFeeToken();
          _returnFunds(token, 0);
      }
  
      function rescueTokensExact(IERC20[] calldata tokens, uint256[] calldata amounts) external onlyOwner {
          // NOTE: amounts in contract must be fetched and encoded off-chain
          for (uint256 i = 0; i < tokens.length; i++) {
              if (address(tokens[i]) == address(_buyToken)) revert OwnerCannotRescueFeeToken();
              _returnFunds(tokens[i], amounts[i]);
          }
      }
  
      function retrieveFees() external onlyManager {
          _returnFunds(_buyToken, 0);
      }
  
      function _returnFunds(IERC20 token, uint256 amount) internal {
          if (address(token) == ETH_TOKEN) {
              if (amount == 0) amount = address(this).balance;
              payable(msg.sender).transfer(amount);
          } else {
              if (amount == 0) amount = token.balanceOf(address(this));
              token.safeTransfer(msg.sender, amount);
          }
      }
  
      // Functions: order execution
  
      /// @notice Execute a swap against the target pool
      /// @dev Assumes usage within a multicall context.
      ///      Callable only by a whitelisted solver.
      ///      Requires the sell tokens to be available in the contract before invocation.
      ///      Any extra incentives (extra sell tokens) are calculated off-chain and included as part
      ///      of executeData's dx param.
      ///      Will unwrap held WETH into ETH if sell token is ETH.
      /// @param executeData encoded bytes as (int128, int128, uint256, uint256, address, address, uint256):
      ///          i (int128): ICurvePlainPool.exchange()'s i argument (index of coin to swap from)
      ///          j (int128): ICurvePlainPool.exchange()'s j argument (index of coin to swap to)
      ///          dx (uint256): ICurvePlainPool.exchange()'s dx argument (amount of coin i to swap)
      ///          netDy (uint256): amount of coin y to send to settlement target, net of solver fee
      ///          settlement (address): settlement target receiving coin j, must be within whitelisted settlements
      ///          iToken (address): address of coin i, optional to save gas
      ///          jToken (address): address of coin j, optional to save gas
      function targetPoolExecuteOrder(bytes calldata executeData) external onlySolvers {
          (int128 i, int128 j, uint256 dx, uint256 netDy, address settlement, address iToken, address jToken) =
              abi.decode(executeData, (int128, int128, uint256, uint256, address, address, address));
  
          if (!_settlements.contains(settlement)) revert OnlySettlements();
  
          if (iToken == address(0)) iToken = _targetPool.coins(SafeCast.toUint256(int256(i)));
          if (jToken == address(0)) jToken = _targetPool.coins(SafeCast.toUint256(int256(j)));
          if (jToken != address(_buyToken)) revert BuyTokenIncorrect(jToken);
  
          if (iToken == WETH_TOKEN && address(this).balance < dx) WETH9.withdraw(dx);
  
          // Note: curve pools before v0.3.0 (approx spring/summer 2021) do not include the additional
          //       ICurvePlainPool.exchange(i, j, dx, minDy, receiver) overload
          uint256 dy =_targetPool.exchange{value: dx}(i, j, dx, netDy);
          if (jToken == ETH_TOKEN) {
              payable(settlement).transfer(netDy);
          } else {
              IERC20(jToken).safeTransfer(settlement, netDy);
          }
          emit OrderExecuted(netDy, dy - netDy);
      }
  }