ETH Price: $2,594.92 (+0.70%)

Transaction Decoder

Block:
22716441 at Jun-16-2025 10:19:59 AM +UTC
Transaction Fee:
0.000267994527957 ETH $0.70
Gas Used:
193,700 Gas / 1.38355461 Gwei

Emitted Events:

223 AltLayerToken.Transfer( from=[Sender] 0x542714c4a85b7c67f73a400cce7381b3082175f2, to=UniswapV2Pair, value=608117500346052132430 )
224 TetherToken.Transfer( from=UniswapV2Pair, to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, value=31127819 )
225 UniswapV2Pair.Sync( reserve0=2182481445670621589524231, reserve1=112020000701 )
226 UniswapV2Pair.Swap( sender=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, amount0In=608117500346052132430, amount1In=0, amount0Out=0, amount1Out=31127819, to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C )
227 TetherToken.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=TokenChwomper, value=1099365 )
228 0x3ced11c610556e5292fbc2e75d68c3899098c14c.0xbbb02a24579dc2e59c1609253b6ddab5457ba00895b3eda80dd41e03e2cd7e55( 0xbbb02a24579dc2e59c1609253b6ddab5457ba00895b3eda80dd41e03e2cd7e55, 0x000000000000000000000000ad27827c312cd5e71311d68e180a9872d42de23d, 0x0000000000000000000000008457ca5040ad67fdebbcc8edce889a335bc0fbfb, 0x0000000000000000000000000000000000000000000000000000000000000001, 0000000000000000000000003ced11c610556e5292fbc2e75d68c3899098c14c, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 000000000000000000000000000000000000000000000020f7535c9ec0ec3e4e, 0000000000000000000000000000000000000000000000000000000001ca32a6, 000000000000000000000000000000000000000000000000000000000010c665 )
229 TetherToken.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=TokenChwomper, value=14939 )
230 TetherToken.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=TokenChwomper, value=59756 )
231 TetherToken.Transfer( from=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, to=[Sender] 0x542714c4a85b7c67f73a400cce7381b3082175f2, value=29953759 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
8.745293388142040137 Eth8.745390238142040137 Eth0.00009685
0x542714c4...3082175f2
0.009040910186641636 Eth
Nonce: 189
0.008772915658684636 Eth
Nonce: 190
0.000267994527957
0x65680A98...7e6aA8068
0x8457CA50...35Bc0fbFB
0xdAC17F95...13D831ec7

Execution Trace

RedSnwapper.snwapMultiple( inputTokens=, outputTokens=, executors= ) => ( amountOut=[29953759] )
  • TetherToken.balanceOf( who=0x542714c4A85b7c67f73a400Cce7381b3082175f2 ) => ( 0 )
  • AltLayerToken.transferFrom( from=0x542714c4A85b7c67f73a400Cce7381b3082175f2, to=0x65680A987f4871a7bB865C86FaE11667e6aA8068, value=608117500346052132430 ) => ( True )
  • 0xad27827c312cd5e71311d68e180a9872d42de23d.e8ff45ca( )
    • 0x3ced11c610556e5292fbc2e75d68c3899098c14c.ba3f2165( )
      • TetherToken.balanceOf( who=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 1 )
      • AltLayerToken.balanceOf( account=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 1 )
      • UniswapV2Pair.STATICCALL( )
      • AltLayerToken.balanceOf( account=0x65680A987f4871a7bB865C86FaE11667e6aA8068 ) => ( 2182481445670621589524231 )
      • UniswapV2Pair.swap( amount0Out=0, amount1Out=31127819, to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, data=0x )
        • TetherToken.transfer( _to=0x3Ced11c610556e5292fBC2e75D68c3899098C14C, _value=31127819 )
        • AltLayerToken.balanceOf( account=0x65680A987f4871a7bB865C86FaE11667e6aA8068 ) => ( 2182481445670621589524231 )
        • TetherToken.balanceOf( who=0x65680A987f4871a7bB865C86FaE11667e6aA8068 ) => ( 112020000701 )
        • TetherToken.balanceOf( who=0x3Ced11c610556e5292fBC2e75D68c3899098C14C ) => ( 31127820 )
        • TetherToken.transfer( _to=0x5C2e112783A6854653B4BC7DC22248D3e592559C, _value=1099365 )
        • TetherToken.transfer( _to=0xde7259893Af7cdbC9fD806c6ba61D22D581d5667, _value=14939 )
        • TetherToken.transfer( _to=0xde7259893Af7cdbC9fD806c6ba61D22D581d5667, _value=59756 )
        • TetherToken.transfer( _to=0x542714c4A85b7c67f73a400Cce7381b3082175f2, _value=29953759 )
        • TetherToken.balanceOf( who=0x542714c4A85b7c67f73a400Cce7381b3082175f2 ) => ( 29953759 )
          snwapMultiple[RedSnwapper (ln:500)]
          File 1 of 6: RedSnwapper
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
           *
           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
           * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
           * need to send a transaction, and thus is not required to hold Ether at all.
           */
          interface IERC20Permit {
              /**
               * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
               * given ``owner``'s signed approval.
               *
               * IMPORTANT: The same issues {IERC20-approve} has related to transaction
               * ordering also apply here.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               * - `deadline` must be a timestamp in the future.
               * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
               * over the EIP712-formatted function arguments.
               * - the signature must use ``owner``'s current nonce (see {nonces}).
               *
               * For more information on the signature format, see the
               * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
               * section].
               */
              function permit(
                  address owner,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) external;
              /**
               * @dev Returns the current nonce for `owner`. This value must be
               * included whenever a signature is generated for {permit}.
               *
               * Every successful call to {permit} increases ``owner``'s nonce by one. This
               * prevents a signature from being used multiple times.
               */
              function nonces(address owner) external view returns (uint256);
              /**
               * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
               */
              // solhint-disable-next-line func-name-mixedcase
              function DOMAIN_SEPARATOR() external view returns (bytes32);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
          pragma solidity ^0.8.0;
          /**
           * @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 amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `to`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address to, uint256 amount) external returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender) external view returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `from` to `to` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address from,
                  address to,
                  uint256 amount
              ) external returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
          pragma solidity ^0.8.0;
          import "../IERC20.sol";
          import "../extensions/draft-IERC20Permit.sol";
          import "../../../utils/Address.sol";
          /**
           * @title SafeERC20
           * @dev Wrappers around ERC20 operations that throw on failure (when the token
           * contract returns false). Tokens that return no value (and instead revert or
           * throw on failure) are also supported, non-reverting calls are assumed to be
           * successful.
           * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
           * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
           */
          library SafeERC20 {
              using Address for address;
              function safeTransfer(
                  IERC20 token,
                  address to,
                  uint256 value
              ) internal {
                  _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
              }
              function safeTransferFrom(
                  IERC20 token,
                  address from,
                  address to,
                  uint256 value
              ) internal {
                  _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
              }
              /**
               * @dev Deprecated. This function has issues similar to the ones found in
               * {IERC20-approve}, and its usage is discouraged.
               *
               * Whenever possible, use {safeIncreaseAllowance} and
               * {safeDecreaseAllowance} instead.
               */
              function safeApprove(
                  IERC20 token,
                  address spender,
                  uint256 value
              ) internal {
                  // safeApprove should only be called when setting an initial allowance,
                  // or when resetting it to zero. To increase and decrease it, use
                  // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                  require(
                      (value == 0) || (token.allowance(address(this), spender) == 0),
                      "SafeERC20: approve from non-zero to non-zero allowance"
                  );
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
              }
              function safeIncreaseAllowance(
                  IERC20 token,
                  address spender,
                  uint256 value
              ) internal {
                  uint256 newAllowance = token.allowance(address(this), spender) + value;
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
              function safeDecreaseAllowance(
                  IERC20 token,
                  address spender,
                  uint256 value
              ) internal {
                  unchecked {
                      uint256 oldAllowance = token.allowance(address(this), spender);
                      require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                      uint256 newAllowance = oldAllowance - value;
                      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                  }
              }
              function safePermit(
                  IERC20Permit token,
                  address owner,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) internal {
                  uint256 nonceBefore = token.nonces(owner);
                  token.permit(owner, spender, value, deadline, v, r, s);
                  uint256 nonceAfter = token.nonces(owner);
                  require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
              }
              /**
               * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
               * on the return value: the return value is optional (but if data is returned, it must not be false).
               * @param token The token targeted by the call.
               * @param data The call data (encoded using abi.encode or one of its variants).
               */
              function _callOptionalReturn(IERC20 token, bytes memory data) private {
                  // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                  // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
                  // the target address contains contract code and also asserts for success in the low-level call.
                  bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                  if (returndata.length > 0) {
                      // Return data is optional
                      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
          pragma solidity ^0.8.1;
          /**
           * @dev Collection of functions related to the address type
           */
          library Address {
              /**
               * @dev Returns true if `account` is a contract.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               *
               * [IMPORTANT]
               * ====
               * You shouldn't rely on `isContract` to protect against flash loan attacks!
               *
               * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
               * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
               * constructor.
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize/address.code.length, which returns 0
                  // for contracts in construction, since the code is only stored at the end
                  // of the constructor execution.
                  return account.code.length > 0;
              }
              /**
               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
               * `recipient`, forwarding all available gas and reverting on errors.
               *
               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
               * of certain opcodes, possibly making contracts go over the 2300 gas limit
               * imposed by `transfer`, making them unable to receive funds via
               * `transfer`. {sendValue} removes this limitation.
               *
               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
               *
               * IMPORTANT: because control is transferred to `recipient`, care must be
               * taken to not create reentrancy vulnerabilities. Consider using
               * {ReentrancyGuard} or the
               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
               */
              function sendValue(address payable recipient, uint256 amount) internal {
                  require(address(this).balance >= amount, "Address: insufficient balance");
                  (bool success, ) = recipient.call{value: amount}("");
                  require(success, "Address: unable to send value, recipient may have reverted");
              }
              /**
               * @dev Performs a Solidity function call using a low level `call`. A
               * plain `call` is an unsafe replacement for a function call: use this
               * function instead.
               *
               * If `target` reverts with a revert reason, it is bubbled up by this
               * function (like regular Solidity function calls).
               *
               * Returns the raw returned data. To convert to the expected return value,
               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
               *
               * Requirements:
               *
               * - `target` must be a contract.
               * - calling `target` with `data` must not revert.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, 0, "Address: low-level call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
               * `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCall(
                  address target,
                  bytes memory data,
                  string memory errorMessage
              ) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, 0, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but also transferring `value` wei to `target`.
               *
               * Requirements:
               *
               * - the calling contract must have an ETH balance of at least `value`.
               * - the called Solidity function must be `payable`.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(
                  address target,
                  bytes memory data,
                  uint256 value
              ) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
              }
              /**
               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
               * with `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(
                  address target,
                  bytes memory data,
                  uint256 value,
                  string memory errorMessage
              ) internal returns (bytes memory) {
                  require(address(this).balance >= value, "Address: insufficient balance for call");
                  (bool success, bytes memory returndata) = target.call{value: value}(data);
                  return verifyCallResultFromTarget(target, success, returndata, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                  return functionStaticCall(target, data, "Address: low-level static call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(
                  address target,
                  bytes memory data,
                  string memory errorMessage
              ) internal view returns (bytes memory) {
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return verifyCallResultFromTarget(target, success, returndata, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but performing a delegate call.
               *
               * _Available since v3.4._
               */
              function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                  return functionDelegateCall(target, data, "Address: low-level delegate call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
               * but performing a delegate call.
               *
               * _Available since v3.4._
               */
              function functionDelegateCall(
                  address target,
                  bytes memory data,
                  string memory errorMessage
              ) internal returns (bytes memory) {
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return verifyCallResultFromTarget(target, success, returndata, errorMessage);
              }
              /**
               * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
               * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
               *
               * _Available since v4.8._
               */
              function verifyCallResultFromTarget(
                  address target,
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal view returns (bytes memory) {
                  if (success) {
                      if (returndata.length == 0) {
                          // only check isContract if the call was successful and the return data is empty
                          // otherwise we already know that it was a contract
                          require(isContract(target), "Address: call to non-contract");
                      }
                      return returndata;
                  } else {
                      _revert(returndata, errorMessage);
                  }
              }
              /**
               * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
               * revert reason or using the provided one.
               *
               * _Available since v4.3._
               */
              function verifyCallResult(
                  bool success,
                  bytes memory returndata,
                  string memory errorMessage
              ) internal pure returns (bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      _revert(returndata, errorMessage);
                  }
              }
              function _revert(bytes memory returndata, string memory errorMessage) private pure {
                  // Look for revert reason and bubble it up if present
                  if (returndata.length > 0) {
                      // The easiest way to bubble the revert reason is using memory via assembly
                      /// @solidity memory-safe-assembly
                      assembly {
                          let returndata_size := mload(returndata)
                          revert(add(32, returndata), returndata_size)
                      }
                  } else {
                      revert(errorMessage);
                  }
              }
          }
          // SPDX-License-Identifier: UNLICENSED
          pragma solidity 0.8.24;
          import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
          contract RedSnwapper {
            using SafeERC20 for IERC20;
            using Utils for IERC20;
            SafeExecutor public immutable safeExecutor;
            constructor() {
              safeExecutor = new SafeExecutor();
            }
            // @notice Swaps tokens
            // @notice 1. Transfers amountIn of tokens tokenIn to executor
            // @notice 2. launches executor with executorData and value = msg.value
            // @notice 3. Checks that recipient's tokenOut balance was increased at least amountOutMin
            function snwap(
              IERC20 tokenIn,
              uint amountIn, // if amountIn == 0 then amountIn = tokenIn.balance(this) - 1
              address recipient,
              IERC20 tokenOut,
              uint amountOutMin,
              address executor,
              bytes calldata executorData
            ) external payable returns (uint amountOut) {
              uint initialOutputBalance = tokenOut.universalBalanceOf(recipient);
              if (address(tokenIn) != NATIVE_ADDRESS) {
                if (amountIn > 0) tokenIn.safeTransferFrom(msg.sender, executor, amountIn);
                else tokenIn.safeTransfer(executor, tokenIn.balanceOf(address(this)) - 1); // -1 is slot undrain protection
              }
              safeExecutor.execute{value: msg.value}(executor, executorData);
              amountOut = tokenOut.universalBalanceOf(recipient) - initialOutputBalance;
              if (amountOut < amountOutMin)
                revert MinimalOutputBalanceViolation(address(tokenOut), amountOut);
            }
            // @notice Swaps multiple tokens
            // @notice 1. Transfers inputTokens to inputTokens[i].transferTo
            // @notice 2. launches executors
            // @notice 3. Checks that recipient's tokenOut balance was increased at least amountOutMin
            function snwapMultiple(
              InputToken[] calldata inputTokens,
              OutputToken[] calldata outputTokens,
              Executor[] calldata executors
            ) external payable returns (uint[] memory amountOut) {
              uint[] memory initialOutputBalance = new uint[](outputTokens.length);
              for (uint i = 0; i < outputTokens.length; i++) {
                initialOutputBalance[i] = outputTokens[i].token.universalBalanceOf(outputTokens[i].recipient);
              }
              for (uint i = 0; i < inputTokens.length; i++) {
                IERC20 tokenIn = inputTokens[i].token;
                if (address(tokenIn) != NATIVE_ADDRESS) {
                  if (inputTokens[i].amountIn > 0) 
                    tokenIn.safeTransferFrom(msg.sender, inputTokens[i].transferTo, inputTokens[i].amountIn);
                  else tokenIn.safeTransfer(inputTokens[i].transferTo, tokenIn.balanceOf(address(this)) - 1); // -1 is slot undrain protection
                }
              }
              safeExecutor.executeMultiple{value: msg.value}(executors);
              amountOut = new uint[](outputTokens.length);
              for (uint i = 0; i < outputTokens.length; i++) {
                amountOut[i] = outputTokens[i].token.universalBalanceOf(outputTokens[i].recipient) - initialOutputBalance[i];
                if (amountOut[i] < outputTokens[i].amountOutMin)
                  revert MinimalOutputBalanceViolation(address(outputTokens[i].token), amountOut[i]);
              }
            }
          }
          // This contract doesn't have token approves, so can safely call other contracts
          contract SafeExecutor {  
            using Utils for address;
            function execute(address executor, bytes calldata executorData) external payable {
              executor.callRevertBubbleUp(msg.value, executorData);
            }
            function executeMultiple(Executor[] calldata executors) external payable {
              for (uint i = 0; i < executors.length; i++) {
                executors[i].executor.callRevertBubbleUp(executors[i].value, executors[i].data);
              }
            }
          }
          error MinimalOutputBalanceViolation(address tokenOut, uint256 amountOut);
          address constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
          struct InputToken {
            IERC20 token;
            uint amountIn;
            address transferTo;
          }
          struct OutputToken {
            IERC20 token;
            address recipient;
            uint amountOutMin;
          }
          struct Executor {
            address executor;
            uint value;
            bytes data;
          }
          library Utils {
            using SafeERC20 for IERC20;
            
            function universalBalanceOf(IERC20 token, address user) internal view returns (uint256) {
              if (address(token) == NATIVE_ADDRESS) return address(user).balance;
              else return token.balanceOf(user);
            }
            function callRevertBubbleUp(address contr, uint256 value, bytes memory data) internal {
              (bool success, bytes memory returnBytes) = contr.call{value: value}(data);
              if (!success) {
                assembly {
                  revert(add(32, returnBytes), mload(returnBytes))
                }
              }
            }
          }

          File 2 of 6: UniswapV2Pair
          // File: contracts/interfaces/IUniswapV2Pair.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Pair {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external pure returns (string memory);
              function symbol() external pure returns (string memory);
              function decimals() external pure returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          
              function DOMAIN_SEPARATOR() external view returns (bytes32);
              function PERMIT_TYPEHASH() external pure returns (bytes32);
              function nonces(address owner) external view returns (uint);
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
          
              event Mint(address indexed sender, uint amount0, uint amount1);
              event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
              event Swap(
                  address indexed sender,
                  uint amount0In,
                  uint amount1In,
                  uint amount0Out,
                  uint amount1Out,
                  address indexed to
              );
              event Sync(uint112 reserve0, uint112 reserve1);
          
              function MINIMUM_LIQUIDITY() external pure returns (uint);
              function factory() external view returns (address);
              function token0() external view returns (address);
              function token1() external view returns (address);
              function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
              function price0CumulativeLast() external view returns (uint);
              function price1CumulativeLast() external view returns (uint);
              function kLast() external view returns (uint);
          
              function mint(address to) external returns (uint liquidity);
              function burn(address to) external returns (uint amount0, uint amount1);
              function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
              function skim(address to) external;
              function sync() external;
          
              function initialize(address, address) external;
          }
          
          // File: contracts/interfaces/IUniswapV2ERC20.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2ERC20 {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external pure returns (string memory);
              function symbol() external pure returns (string memory);
              function decimals() external pure returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          
              function DOMAIN_SEPARATOR() external view returns (bytes32);
              function PERMIT_TYPEHASH() external pure returns (bytes32);
              function nonces(address owner) external view returns (uint);
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
          }
          
          // File: contracts/libraries/SafeMath.sol
          
          pragma solidity =0.5.16;
          
          // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
          
          library SafeMath {
              function add(uint x, uint y) internal pure returns (uint z) {
                  require((z = x + y) >= x, 'ds-math-add-overflow');
              }
          
              function sub(uint x, uint y) internal pure returns (uint z) {
                  require((z = x - y) <= x, 'ds-math-sub-underflow');
              }
          
              function mul(uint x, uint y) internal pure returns (uint z) {
                  require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
              }
          }
          
          // File: contracts/UniswapV2ERC20.sol
          
          pragma solidity =0.5.16;
          
          
          
          contract UniswapV2ERC20 is IUniswapV2ERC20 {
              using SafeMath for uint;
          
              string public constant name = 'Uniswap V2';
              string public constant symbol = 'UNI-V2';
              uint8 public constant decimals = 18;
              uint  public totalSupply;
              mapping(address => uint) public balanceOf;
              mapping(address => mapping(address => uint)) public allowance;
          
              bytes32 public DOMAIN_SEPARATOR;
              // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
              bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
              mapping(address => uint) public nonces;
          
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              constructor() public {
                  uint chainId;
                  assembly {
                      chainId := chainid
                  }
                  DOMAIN_SEPARATOR = keccak256(
                      abi.encode(
                          keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                          keccak256(bytes(name)),
                          keccak256(bytes('1')),
                          chainId,
                          address(this)
                      )
                  );
              }
          
              function _mint(address to, uint value) internal {
                  totalSupply = totalSupply.add(value);
                  balanceOf[to] = balanceOf[to].add(value);
                  emit Transfer(address(0), to, value);
              }
          
              function _burn(address from, uint value) internal {
                  balanceOf[from] = balanceOf[from].sub(value);
                  totalSupply = totalSupply.sub(value);
                  emit Transfer(from, address(0), value);
              }
          
              function _approve(address owner, address spender, uint value) private {
                  allowance[owner][spender] = value;
                  emit Approval(owner, spender, value);
              }
          
              function _transfer(address from, address to, uint value) private {
                  balanceOf[from] = balanceOf[from].sub(value);
                  balanceOf[to] = balanceOf[to].add(value);
                  emit Transfer(from, to, value);
              }
          
              function approve(address spender, uint value) external returns (bool) {
                  _approve(msg.sender, spender, value);
                  return true;
              }
          
              function transfer(address to, uint value) external returns (bool) {
                  _transfer(msg.sender, to, value);
                  return true;
              }
          
              function transferFrom(address from, address to, uint value) external returns (bool) {
                  if (allowance[from][msg.sender] != uint(-1)) {
                      allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
                  }
                  _transfer(from, to, value);
                  return true;
              }
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
                  require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
                  bytes32 digest = keccak256(
                      abi.encodePacked(
                          '\x19\x01',
                          DOMAIN_SEPARATOR,
                          keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                      )
                  );
                  address recoveredAddress = ecrecover(digest, v, r, s);
                  require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
                  _approve(owner, spender, value);
              }
          }
          
          // File: contracts/libraries/Math.sol
          
          pragma solidity =0.5.16;
          
          // a library for performing various math operations
          
          library Math {
              function min(uint x, uint y) internal pure returns (uint z) {
                  z = x < y ? x : y;
              }
          
              // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
              function sqrt(uint y) internal pure returns (uint z) {
                  if (y > 3) {
                      z = y;
                      uint x = y / 2 + 1;
                      while (x < z) {
                          z = x;
                          x = (y / x + x) / 2;
                      }
                  } else if (y != 0) {
                      z = 1;
                  }
              }
          }
          
          // File: contracts/libraries/UQ112x112.sol
          
          pragma solidity =0.5.16;
          
          // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
          
          // range: [0, 2**112 - 1]
          // resolution: 1 / 2**112
          
          library UQ112x112 {
              uint224 constant Q112 = 2**112;
          
              // encode a uint112 as a UQ112x112
              function encode(uint112 y) internal pure returns (uint224 z) {
                  z = uint224(y) * Q112; // never overflows
              }
          
              // divide a UQ112x112 by a uint112, returning a UQ112x112
              function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
                  z = x / uint224(y);
              }
          }
          
          // File: contracts/interfaces/IERC20.sol
          
          pragma solidity >=0.5.0;
          
          interface IERC20 {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external view returns (string memory);
              function symbol() external view returns (string memory);
              function decimals() external view returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          }
          
          // File: contracts/interfaces/IUniswapV2Factory.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Factory {
              event PairCreated(address indexed token0, address indexed token1, address pair, uint);
          
              function feeTo() external view returns (address);
              function feeToSetter() external view returns (address);
          
              function getPair(address tokenA, address tokenB) external view returns (address pair);
              function allPairs(uint) external view returns (address pair);
              function allPairsLength() external view returns (uint);
          
              function createPair(address tokenA, address tokenB) external returns (address pair);
          
              function setFeeTo(address) external;
              function setFeeToSetter(address) external;
          }
          
          // File: contracts/interfaces/IUniswapV2Callee.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Callee {
              function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
          }
          
          // File: contracts/UniswapV2Pair.sol
          
          pragma solidity =0.5.16;
          
          
          
          
          
          
          
          
          contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
              using SafeMath  for uint;
              using UQ112x112 for uint224;
          
              uint public constant MINIMUM_LIQUIDITY = 10**3;
              bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
          
              address public factory;
              address public token0;
              address public token1;
          
              uint112 private reserve0;           // uses single storage slot, accessible via getReserves
              uint112 private reserve1;           // uses single storage slot, accessible via getReserves
              uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
          
              uint public price0CumulativeLast;
              uint public price1CumulativeLast;
              uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
          
              uint private unlocked = 1;
              modifier lock() {
                  require(unlocked == 1, 'UniswapV2: LOCKED');
                  unlocked = 0;
                  _;
                  unlocked = 1;
              }
          
              function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
                  _reserve0 = reserve0;
                  _reserve1 = reserve1;
                  _blockTimestampLast = blockTimestampLast;
              }
          
              function _safeTransfer(address token, address to, uint value) private {
                  (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
                  require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
              }
          
              event Mint(address indexed sender, uint amount0, uint amount1);
              event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
              event Swap(
                  address indexed sender,
                  uint amount0In,
                  uint amount1In,
                  uint amount0Out,
                  uint amount1Out,
                  address indexed to
              );
              event Sync(uint112 reserve0, uint112 reserve1);
          
              constructor() public {
                  factory = msg.sender;
              }
          
              // called once by the factory at time of deployment
              function initialize(address _token0, address _token1) external {
                  require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
                  token0 = _token0;
                  token1 = _token1;
              }
          
              // update reserves and, on the first call per block, price accumulators
              function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
                  require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
                  uint32 blockTimestamp = uint32(block.timestamp % 2**32);
                  uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
                  if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                      // * never overflows, and + overflow is desired
                      price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                      price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
                  }
                  reserve0 = uint112(balance0);
                  reserve1 = uint112(balance1);
                  blockTimestampLast = blockTimestamp;
                  emit Sync(reserve0, reserve1);
              }
          
              // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
              function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
                  address feeTo = IUniswapV2Factory(factory).feeTo();
                  feeOn = feeTo != address(0);
                  uint _kLast = kLast; // gas savings
                  if (feeOn) {
                      if (_kLast != 0) {
                          uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                          uint rootKLast = Math.sqrt(_kLast);
                          if (rootK > rootKLast) {
                              uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                              uint denominator = rootK.mul(5).add(rootKLast);
                              uint liquidity = numerator / denominator;
                              if (liquidity > 0) _mint(feeTo, liquidity);
                          }
                      }
                  } else if (_kLast != 0) {
                      kLast = 0;
                  }
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function mint(address to) external lock returns (uint liquidity) {
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  uint balance0 = IERC20(token0).balanceOf(address(this));
                  uint balance1 = IERC20(token1).balanceOf(address(this));
                  uint amount0 = balance0.sub(_reserve0);
                  uint amount1 = balance1.sub(_reserve1);
          
                  bool feeOn = _mintFee(_reserve0, _reserve1);
                  uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                  if (_totalSupply == 0) {
                      liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                     _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                  } else {
                      liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
                  }
                  require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
                  _mint(to, liquidity);
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                  emit Mint(msg.sender, amount0, amount1);
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function burn(address to) external lock returns (uint amount0, uint amount1) {
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  address _token0 = token0;                                // gas savings
                  address _token1 = token1;                                // gas savings
                  uint balance0 = IERC20(_token0).balanceOf(address(this));
                  uint balance1 = IERC20(_token1).balanceOf(address(this));
                  uint liquidity = balanceOf[address(this)];
          
                  bool feeOn = _mintFee(_reserve0, _reserve1);
                  uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                  amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
                  amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
                  require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
                  _burn(address(this), liquidity);
                  _safeTransfer(_token0, to, amount0);
                  _safeTransfer(_token1, to, amount1);
                  balance0 = IERC20(_token0).balanceOf(address(this));
                  balance1 = IERC20(_token1).balanceOf(address(this));
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                  emit Burn(msg.sender, amount0, amount1, to);
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
                  require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
          
                  uint balance0;
                  uint balance1;
                  { // scope for _token{0,1}, avoids stack too deep errors
                  address _token0 = token0;
                  address _token1 = token1;
                  require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
                  if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
                  if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
                  if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
                  balance0 = IERC20(_token0).balanceOf(address(this));
                  balance1 = IERC20(_token1).balanceOf(address(this));
                  }
                  uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
                  uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
                  require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
                  { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
                  uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
                  uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
                  require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
                  }
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
              }
          
              // force balances to match reserves
              function skim(address to) external lock {
                  address _token0 = token0; // gas savings
                  address _token1 = token1; // gas savings
                  _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
                  _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
              }
          
              // force reserves to match balances
              function sync() external lock {
                  _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
              }
          }

          File 3 of 6: AltLayerToken
          // SPDX-License-Identifier: MIT
          pragma solidity =0.8.23;
          import {ERC20, ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
          import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
          import {ERC20Capped} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";
          import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
          import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
          /// @title AltLayer Token Contract
          /// @notice Implements an ERC20 token with a cap, burnability, pausability, and ownership features
          contract AltLayerToken is
              ERC20Burnable,
              ERC20Permit,
              ERC20Capped,
              ERC20Pausable,
              Ownable
          {
              /// @notice Initializes the contract with a name, symbol, cap, and initial owner
              /// @param initialOwner The address to be set as the initial owner of the token
              constructor(
                  address initialOwner
              )
                  ERC20("AltLayer Token", "ALT")
                  ERC20Permit("AltLayer Token")
                  ERC20Capped(1e28)
                  Ownable(initialOwner)
              {}
              /// @notice Allows the owner to pause all token transfers
              function pause() external onlyOwner {
                  _pause();
              }
              /// @notice Allows the owner to unpause the token transfers
              function unpause() external onlyOwner {
                  _unpause();
              }
              /// @notice Allows the owner to mint new tokens, up to the cap
              /// @param to The address that will receive the minted tokens
              /// @param amount The amount of tokens to mint
              function mint(address to, uint256 amount) external onlyOwner {
                  _mint(to, amount);
              }
              /// @dev Internal function to update state during transfers, respecting the cap and pausability
              /// @param from The address sending the tokens
              /// @param to The address receiving the tokens
              /// @param value The amount of tokens being transferred
              function _update(
                  address from,
                  address to,
                  uint256 value
              ) internal override(ERC20, ERC20Capped, ERC20Pausable) {
                  super._update(from, to, value);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
          pragma solidity ^0.8.20;
          import {ERC20} from "../ERC20.sol";
          import {Context} from "../../../utils/Context.sol";
          /**
           * @dev Extension of {ERC20} that allows token holders to destroy both their own
           * tokens and those that they have an allowance for, in a way that can be
           * recognized off-chain (via event analysis).
           */
          abstract contract ERC20Burnable is Context, ERC20 {
              /**
               * @dev Destroys a `value` amount of tokens from the caller.
               *
               * See {ERC20-_burn}.
               */
              function burn(uint256 value) public virtual {
                  _burn(_msgSender(), value);
              }
              /**
               * @dev Destroys a `value` amount of tokens from `account`, deducting from
               * the caller's allowance.
               *
               * See {ERC20-_burn} and {ERC20-allowance}.
               *
               * Requirements:
               *
               * - the caller must have allowance for ``accounts``'s tokens of at least
               * `value`.
               */
              function burnFrom(address account, uint256 value) public virtual {
                  _spendAllowance(account, _msgSender(), value);
                  _burn(account, value);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)
          pragma solidity ^0.8.20;
          import {IERC20Permit} from "./IERC20Permit.sol";
          import {ERC20} from "../ERC20.sol";
          import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
          import {EIP712} from "../../../utils/cryptography/EIP712.sol";
          import {Nonces} from "../../../utils/Nonces.sol";
          /**
           * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
           * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
           *
           * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
           * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
           * need to send a transaction, and thus is not required to hold Ether at all.
           */
          abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
              bytes32 private constant PERMIT_TYPEHASH =
                  keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
              /**
               * @dev Permit deadline has expired.
               */
              error ERC2612ExpiredSignature(uint256 deadline);
              /**
               * @dev Mismatched signature.
               */
              error ERC2612InvalidSigner(address signer, address owner);
              /**
               * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
               *
               * It's a good idea to use the same `name` that is defined as the ERC20 token name.
               */
              constructor(string memory name) EIP712(name, "1") {}
              /**
               * @inheritdoc IERC20Permit
               */
              function permit(
                  address owner,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) public virtual {
                  if (block.timestamp > deadline) {
                      revert ERC2612ExpiredSignature(deadline);
                  }
                  bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
                  bytes32 hash = _hashTypedDataV4(structHash);
                  address signer = ECDSA.recover(hash, v, r, s);
                  if (signer != owner) {
                      revert ERC2612InvalidSigner(signer, owner);
                  }
                  _approve(owner, spender, value);
              }
              /**
               * @inheritdoc IERC20Permit
               */
              function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
                  return super.nonces(owner);
              }
              /**
               * @inheritdoc IERC20Permit
               */
              // solhint-disable-next-line func-name-mixedcase
              function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
                  return _domainSeparatorV4();
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol)
          pragma solidity ^0.8.20;
          import {ERC20} from "../ERC20.sol";
          /**
           * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
           */
          abstract contract ERC20Capped is ERC20 {
              uint256 private immutable _cap;
              /**
               * @dev Total supply cap has been exceeded.
               */
              error ERC20ExceededCap(uint256 increasedSupply, uint256 cap);
              /**
               * @dev The supplied cap is not a valid cap.
               */
              error ERC20InvalidCap(uint256 cap);
              /**
               * @dev Sets the value of the `cap`. This value is immutable, it can only be
               * set once during construction.
               */
              constructor(uint256 cap_) {
                  if (cap_ == 0) {
                      revert ERC20InvalidCap(0);
                  }
                  _cap = cap_;
              }
              /**
               * @dev Returns the cap on the token's total supply.
               */
              function cap() public view virtual returns (uint256) {
                  return _cap;
              }
              /**
               * @dev See {ERC20-_update}.
               */
              function _update(address from, address to, uint256 value) internal virtual override {
                  super._update(from, to, value);
                  if (from == address(0)) {
                      uint256 maxSupply = cap();
                      uint256 supply = totalSupply();
                      if (supply > maxSupply) {
                          revert ERC20ExceededCap(supply, maxSupply);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol)
          pragma solidity ^0.8.20;
          import {ERC20} from "../ERC20.sol";
          import {Pausable} from "../../../utils/Pausable.sol";
          /**
           * @dev ERC20 token with pausable token transfers, minting and burning.
           *
           * Useful for scenarios such as preventing trades until the end of an evaluation
           * period, or having an emergency switch for freezing all token transfers in the
           * event of a large bug.
           *
           * IMPORTANT: This contract does not include public pause and unpause functions. In
           * addition to inheriting this contract, you must define both functions, invoking the
           * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
           * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
           * make the contract pause mechanism of the contract unreachable, and thus unusable.
           */
          abstract contract ERC20Pausable is ERC20, Pausable {
              /**
               * @dev See {ERC20-_update}.
               *
               * Requirements:
               *
               * - the contract must not be paused.
               */
              function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
                  super._update(from, to, value);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
          pragma solidity ^0.8.20;
          import {Context} from "../utils/Context.sol";
          /**
           * @dev Contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * The initial owner is set to the address provided by the deployer. This can
           * later be changed with {transferOwnership}.
           *
           * This module is used through inheritance. It will make available the modifier
           * `onlyOwner`, which can be applied to your functions to restrict their use to
           * the owner.
           */
          abstract contract Ownable is Context {
              address private _owner;
              /**
               * @dev The caller account is not authorized to perform an operation.
               */
              error OwnableUnauthorizedAccount(address account);
              /**
               * @dev The owner is not a valid owner account. (eg. `address(0)`)
               */
              error OwnableInvalidOwner(address owner);
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
               */
              constructor(address initialOwner) {
                  if (initialOwner == address(0)) {
                      revert OwnableInvalidOwner(address(0));
                  }
                  _transferOwnership(initialOwner);
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  _checkOwner();
                  _;
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if the sender is not the owner.
               */
              function _checkOwner() internal view virtual {
                  if (owner() != _msgSender()) {
                      revert OwnableUnauthorizedAccount(_msgSender());
                  }
              }
              /**
               * @dev Leaves the contract without owner. It will not be possible to call
               * `onlyOwner` functions. Can only be called by the current owner.
               *
               * NOTE: Renouncing ownership will leave the contract without an owner,
               * thereby disabling any functionality that is only available to the owner.
               */
              function renounceOwnership() public virtual onlyOwner {
                  _transferOwnership(address(0));
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Can only be called by the current owner.
               */
              function transferOwnership(address newOwner) public virtual onlyOwner {
                  if (newOwner == address(0)) {
                      revert OwnableInvalidOwner(address(0));
                  }
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
          pragma solidity ^0.8.20;
          import {IERC20} from "./IERC20.sol";
          import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
          import {Context} from "../../utils/Context.sol";
          import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
          /**
           * @dev Implementation of the {IERC20} interface.
           *
           * This implementation is agnostic to the way tokens are created. This means
           * that a supply mechanism has to be added in a derived contract using {_mint}.
           *
           * TIP: For a detailed writeup see our guide
           * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
           * to implement supply mechanisms].
           *
           * The default value of {decimals} is 18. To change this, you should override
           * this function so it returns a different value.
           *
           * We have followed general OpenZeppelin Contracts guidelines: functions revert
           * instead returning `false` on failure. This behavior is nonetheless
           * conventional and does not conflict with the expectations of ERC20
           * applications.
           *
           * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
           * This allows applications to reconstruct the allowance for all accounts just
           * by listening to said events. Other implementations of the EIP may not emit
           * these events, as it isn't required by the specification.
           */
          abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
              mapping(address account => uint256) private _balances;
              mapping(address account => mapping(address spender => uint256)) private _allowances;
              uint256 private _totalSupply;
              string private _name;
              string private _symbol;
              /**
               * @dev Sets the values for {name} and {symbol}.
               *
               * All two of these values are immutable: they can only be set once during
               * construction.
               */
              constructor(string memory name_, string memory symbol_) {
                  _name = name_;
                  _symbol = symbol_;
              }
              /**
               * @dev Returns the name of the token.
               */
              function name() public view virtual returns (string memory) {
                  return _name;
              }
              /**
               * @dev Returns the symbol of the token, usually a shorter version of the
               * name.
               */
              function symbol() public view virtual returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev Returns the number of decimals used to get its user representation.
               * For example, if `decimals` equals `2`, a balance of `505` tokens should
               * be displayed to a user as `5.05` (`505 / 10 ** 2`).
               *
               * Tokens usually opt for a value of 18, imitating the relationship between
               * Ether and Wei. This is the default value returned by this function, unless
               * it's overridden.
               *
               * NOTE: This information is only used for _display_ purposes: it in
               * no way affects any of the arithmetic of the contract, including
               * {IERC20-balanceOf} and {IERC20-transfer}.
               */
              function decimals() public view virtual returns (uint8) {
                  return 18;
              }
              /**
               * @dev See {IERC20-totalSupply}.
               */
              function totalSupply() public view virtual returns (uint256) {
                  return _totalSupply;
              }
              /**
               * @dev See {IERC20-balanceOf}.
               */
              function balanceOf(address account) public view virtual returns (uint256) {
                  return _balances[account];
              }
              /**
               * @dev See {IERC20-transfer}.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - the caller must have a balance of at least `value`.
               */
              function transfer(address to, uint256 value) public virtual returns (bool) {
                  address owner = _msgSender();
                  _transfer(owner, to, value);
                  return true;
              }
              /**
               * @dev See {IERC20-allowance}.
               */
              function allowance(address owner, address spender) public view virtual returns (uint256) {
                  return _allowances[owner][spender];
              }
              /**
               * @dev See {IERC20-approve}.
               *
               * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
               * `transferFrom`. This is semantically equivalent to an infinite approval.
               *
               * Requirements:
               *
               * - `spender` cannot be the zero address.
               */
              function approve(address spender, uint256 value) public virtual returns (bool) {
                  address owner = _msgSender();
                  _approve(owner, spender, value);
                  return true;
              }
              /**
               * @dev See {IERC20-transferFrom}.
               *
               * Emits an {Approval} event indicating the updated allowance. This is not
               * required by the EIP. See the note at the beginning of {ERC20}.
               *
               * NOTE: Does not update the allowance if the current allowance
               * is the maximum `uint256`.
               *
               * Requirements:
               *
               * - `from` and `to` cannot be the zero address.
               * - `from` must have a balance of at least `value`.
               * - the caller must have allowance for ``from``'s tokens of at least
               * `value`.
               */
              function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
                  address spender = _msgSender();
                  _spendAllowance(from, spender, value);
                  _transfer(from, to, value);
                  return true;
              }
              /**
               * @dev Moves a `value` amount of tokens from `from` to `to`.
               *
               * This internal function is equivalent to {transfer}, and can be used to
               * e.g. implement automatic token fees, slashing mechanisms, etc.
               *
               * Emits a {Transfer} event.
               *
               * NOTE: This function is not virtual, {_update} should be overridden instead.
               */
              function _transfer(address from, address to, uint256 value) internal {
                  if (from == address(0)) {
                      revert ERC20InvalidSender(address(0));
                  }
                  if (to == address(0)) {
                      revert ERC20InvalidReceiver(address(0));
                  }
                  _update(from, to, value);
              }
              /**
               * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
               * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
               * this function.
               *
               * Emits a {Transfer} event.
               */
              function _update(address from, address to, uint256 value) internal virtual {
                  if (from == address(0)) {
                      // Overflow check required: The rest of the code assumes that totalSupply never overflows
                      _totalSupply += value;
                  } else {
                      uint256 fromBalance = _balances[from];
                      if (fromBalance < value) {
                          revert ERC20InsufficientBalance(from, fromBalance, value);
                      }
                      unchecked {
                          // Overflow not possible: value <= fromBalance <= totalSupply.
                          _balances[from] = fromBalance - value;
                      }
                  }
                  if (to == address(0)) {
                      unchecked {
                          // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                          _totalSupply -= value;
                      }
                  } else {
                      unchecked {
                          // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                          _balances[to] += value;
                      }
                  }
                  emit Transfer(from, to, value);
              }
              /**
               * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
               * Relies on the `_update` mechanism
               *
               * Emits a {Transfer} event with `from` set to the zero address.
               *
               * NOTE: This function is not virtual, {_update} should be overridden instead.
               */
              function _mint(address account, uint256 value) internal {
                  if (account == address(0)) {
                      revert ERC20InvalidReceiver(address(0));
                  }
                  _update(address(0), account, value);
              }
              /**
               * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
               * Relies on the `_update` mechanism.
               *
               * Emits a {Transfer} event with `to` set to the zero address.
               *
               * NOTE: This function is not virtual, {_update} should be overridden instead
               */
              function _burn(address account, uint256 value) internal {
                  if (account == address(0)) {
                      revert ERC20InvalidSender(address(0));
                  }
                  _update(account, address(0), value);
              }
              /**
               * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
               *
               * This internal function is equivalent to `approve`, and can be used to
               * e.g. set automatic allowances for certain subsystems, etc.
               *
               * Emits an {Approval} event.
               *
               * Requirements:
               *
               * - `owner` cannot be the zero address.
               * - `spender` cannot be the zero address.
               *
               * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
               */
              function _approve(address owner, address spender, uint256 value) internal {
                  _approve(owner, spender, value, true);
              }
              /**
               * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
               *
               * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
               * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
               * `Approval` event during `transferFrom` operations.
               *
               * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
               * true using the following override:
               * ```
               * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
               *     super._approve(owner, spender, value, true);
               * }
               * ```
               *
               * Requirements are the same as {_approve}.
               */
              function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
                  if (owner == address(0)) {
                      revert ERC20InvalidApprover(address(0));
                  }
                  if (spender == address(0)) {
                      revert ERC20InvalidSpender(address(0));
                  }
                  _allowances[owner][spender] = value;
                  if (emitEvent) {
                      emit Approval(owner, spender, value);
                  }
              }
              /**
               * @dev Updates `owner` s allowance for `spender` based on spent `value`.
               *
               * Does not update the allowance value in case of infinite allowance.
               * Revert if not enough allowance is available.
               *
               * Does not emit an {Approval} event.
               */
              function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
                  uint256 currentAllowance = allowance(owner, spender);
                  if (currentAllowance != type(uint256).max) {
                      if (currentAllowance < value) {
                          revert ERC20InsufficientAllowance(spender, currentAllowance, value);
                      }
                      unchecked {
                          _approve(owner, spender, currentAllowance - value, false);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
              function _contextSuffixLength() internal view virtual returns (uint256) {
                  return 0;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.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);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
           *
           * These functions can be used to verify that a message was signed by the holder
           * of the private keys of a given address.
           */
          library ECDSA {
              enum RecoverError {
                  NoError,
                  InvalidSignature,
                  InvalidSignatureLength,
                  InvalidSignatureS
              }
              /**
               * @dev The signature derives the `address(0)`.
               */
              error ECDSAInvalidSignature();
              /**
               * @dev The signature has an invalid length.
               */
              error ECDSAInvalidSignatureLength(uint256 length);
              /**
               * @dev The signature has an S value that is in the upper half order.
               */
              error ECDSAInvalidSignatureS(bytes32 s);
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
               * return address(0) without also returning an error description. Errors are documented using an enum (error type)
               * and a bytes32 providing additional information about the error.
               *
               * If no error is returned, then the address can be used for verification purposes.
               *
               * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
               *
               * Documentation for signature generation:
               * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
               * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
               */
              function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
                  if (signature.length == 65) {
                      bytes32 r;
                      bytes32 s;
                      uint8 v;
                      // ecrecover takes the signature parameters, and the only way to get them
                      // currently is to use assembly.
                      /// @solidity memory-safe-assembly
                      assembly {
                          r := mload(add(signature, 0x20))
                          s := mload(add(signature, 0x40))
                          v := byte(0, mload(add(signature, 0x60)))
                      }
                      return tryRecover(hash, v, r, s);
                  } else {
                      return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
                  }
              }
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with
               * `signature`. This address can then be used for verification purposes.
               *
               * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
               */
              function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
                  (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
                  _throwError(error, errorArg);
                  return recovered;
              }
              /**
               * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
               *
               * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
               */
              function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
                  unchecked {
                      bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
                      // We do not check for an overflow here since the shift operation results in 0 or 1.
                      uint8 v = uint8((uint256(vs) >> 255) + 27);
                      return tryRecover(hash, v, r, s);
                  }
              }
              /**
               * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
               */
              function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
                  (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
                  _throwError(error, errorArg);
                  return recovered;
              }
              /**
               * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
               * `r` and `s` signature fields separately.
               */
              function tryRecover(
                  bytes32 hash,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) internal pure returns (address, RecoverError, bytes32) {
                  // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                  // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                  // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
                  // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                  //
                  // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                  // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                  // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                  // these malleable signatures as well.
                  if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
                      return (address(0), RecoverError.InvalidSignatureS, s);
                  }
                  // If the signature is valid (and not malleable), return the signer address
                  address signer = ecrecover(hash, v, r, s);
                  if (signer == address(0)) {
                      return (address(0), RecoverError.InvalidSignature, bytes32(0));
                  }
                  return (signer, RecoverError.NoError, bytes32(0));
              }
              /**
               * @dev Overload of {ECDSA-recover} that receives the `v`,
               * `r` and `s` signature fields separately.
               */
              function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
                  (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
                  _throwError(error, errorArg);
                  return recovered;
              }
              /**
               * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
               */
              function _throwError(RecoverError error, bytes32 errorArg) private pure {
                  if (error == RecoverError.NoError) {
                      return; // no error: do nothing
                  } else if (error == RecoverError.InvalidSignature) {
                      revert ECDSAInvalidSignature();
                  } else if (error == RecoverError.InvalidSignatureLength) {
                      revert ECDSAInvalidSignatureLength(uint256(errorArg));
                  } else if (error == RecoverError.InvalidSignatureS) {
                      revert ECDSAInvalidSignatureS(errorArg);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
          pragma solidity ^0.8.20;
          import {MessageHashUtils} from "./MessageHashUtils.sol";
          import {ShortStrings, ShortString} from "../ShortStrings.sol";
          import {IERC5267} from "../../interfaces/IERC5267.sol";
          /**
           * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
           *
           * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
           * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
           * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
           * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
           *
           * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
           * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
           * ({_hashTypedDataV4}).
           *
           * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
           * the chain id to protect against replay attacks on an eventual fork of the chain.
           *
           * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
           * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
           *
           * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
           * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
           * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
           *
           * @custom:oz-upgrades-unsafe-allow state-variable-immutable
           */
          abstract contract EIP712 is IERC5267 {
              using ShortStrings for *;
              bytes32 private constant TYPE_HASH =
                  keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
              // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
              // invalidate the cached domain separator if the chain id changes.
              bytes32 private immutable _cachedDomainSeparator;
              uint256 private immutable _cachedChainId;
              address private immutable _cachedThis;
              bytes32 private immutable _hashedName;
              bytes32 private immutable _hashedVersion;
              ShortString private immutable _name;
              ShortString private immutable _version;
              string private _nameFallback;
              string private _versionFallback;
              /**
               * @dev Initializes the domain separator and parameter caches.
               *
               * The meaning of `name` and `version` is specified in
               * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
               *
               * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
               * - `version`: the current major version of the signing domain.
               *
               * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
               * contract upgrade].
               */
              constructor(string memory name, string memory version) {
                  _name = name.toShortStringWithFallback(_nameFallback);
                  _version = version.toShortStringWithFallback(_versionFallback);
                  _hashedName = keccak256(bytes(name));
                  _hashedVersion = keccak256(bytes(version));
                  _cachedChainId = block.chainid;
                  _cachedDomainSeparator = _buildDomainSeparator();
                  _cachedThis = address(this);
              }
              /**
               * @dev Returns the domain separator for the current chain.
               */
              function _domainSeparatorV4() internal view returns (bytes32) {
                  if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
                      return _cachedDomainSeparator;
                  } else {
                      return _buildDomainSeparator();
                  }
              }
              function _buildDomainSeparator() private view returns (bytes32) {
                  return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
              }
              /**
               * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
               * function returns the hash of the fully encoded EIP712 message for this domain.
               *
               * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
               *
               * ```solidity
               * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
               *     keccak256("Mail(address to,string contents)"),
               *     mailTo,
               *     keccak256(bytes(mailContents))
               * )));
               * address signer = ECDSA.recover(digest, signature);
               * ```
               */
              function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
                  return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
              }
              /**
               * @dev See {IERC-5267}.
               */
              function eip712Domain()
                  public
                  view
                  virtual
                  returns (
                      bytes1 fields,
                      string memory name,
                      string memory version,
                      uint256 chainId,
                      address verifyingContract,
                      bytes32 salt,
                      uint256[] memory extensions
                  )
              {
                  return (
                      hex"0f", // 01111
                      _EIP712Name(),
                      _EIP712Version(),
                      block.chainid,
                      address(this),
                      bytes32(0),
                      new uint256[](0)
                  );
              }
              /**
               * @dev The name parameter for the EIP712 domain.
               *
               * NOTE: By default this function reads _name which is an immutable value.
               * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
               */
              // solhint-disable-next-line func-name-mixedcase
              function _EIP712Name() internal view returns (string memory) {
                  return _name.toStringWithFallback(_nameFallback);
              }
              /**
               * @dev The version parameter for the EIP712 domain.
               *
               * NOTE: By default this function reads _version which is an immutable value.
               * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
               */
              // solhint-disable-next-line func-name-mixedcase
              function _EIP712Version() internal view returns (string memory) {
                  return _version.toStringWithFallback(_versionFallback);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Provides tracking nonces for addresses. Nonces will only increment.
           */
          abstract contract Nonces {
              /**
               * @dev The nonce used for an `account` is not the expected current nonce.
               */
              error InvalidAccountNonce(address account, uint256 currentNonce);
              mapping(address account => uint256) private _nonces;
              /**
               * @dev Returns the next unused nonce for an address.
               */
              function nonces(address owner) public view virtual returns (uint256) {
                  return _nonces[owner];
              }
              /**
               * @dev Consumes a nonce.
               *
               * Returns the current value and increments nonce.
               */
              function _useNonce(address owner) internal virtual returns (uint256) {
                  // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
                  // decremented or reset. This guarantees that the nonce never overflows.
                  unchecked {
                      // It is important to do x++ and not ++x here.
                      return _nonces[owner]++;
                  }
              }
              /**
               * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
               */
              function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
                  uint256 current = _useNonce(owner);
                  if (nonce != current) {
                      revert InvalidAccountNonce(owner, current);
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
          pragma solidity ^0.8.20;
          import {Context} from "../utils/Context.sol";
          /**
           * @dev Contract module which allows children to implement an emergency stop
           * mechanism that can be triggered by an authorized account.
           *
           * This module is used through inheritance. It will make available the
           * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
           * the functions of your contract. Note that they will not be pausable by
           * simply including this module, only once the modifiers are put in place.
           */
          abstract contract Pausable is Context {
              bool private _paused;
              /**
               * @dev Emitted when the pause is triggered by `account`.
               */
              event Paused(address account);
              /**
               * @dev Emitted when the pause is lifted by `account`.
               */
              event Unpaused(address account);
              /**
               * @dev The operation failed because the contract is paused.
               */
              error EnforcedPause();
              /**
               * @dev The operation failed because the contract is not paused.
               */
              error ExpectedPause();
              /**
               * @dev Initializes the contract in unpaused state.
               */
              constructor() {
                  _paused = false;
              }
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               *
               * Requirements:
               *
               * - The contract must not be paused.
               */
              modifier whenNotPaused() {
                  _requireNotPaused();
                  _;
              }
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               *
               * Requirements:
               *
               * - The contract must be paused.
               */
              modifier whenPaused() {
                  _requirePaused();
                  _;
              }
              /**
               * @dev Returns true if the contract is paused, and false otherwise.
               */
              function paused() public view virtual returns (bool) {
                  return _paused;
              }
              /**
               * @dev Throws if the contract is paused.
               */
              function _requireNotPaused() internal view virtual {
                  if (paused()) {
                      revert EnforcedPause();
                  }
              }
              /**
               * @dev Throws if the contract is not paused.
               */
              function _requirePaused() internal view virtual {
                  if (!paused()) {
                      revert ExpectedPause();
                  }
              }
              /**
               * @dev Triggers stopped state.
               *
               * Requirements:
               *
               * - The contract must not be paused.
               */
              function _pause() internal virtual whenNotPaused {
                  _paused = true;
                  emit Paused(_msgSender());
              }
              /**
               * @dev Returns to normal state.
               *
               * Requirements:
               *
               * - The contract must be paused.
               */
              function _unpause() internal virtual whenPaused {
                  _paused = false;
                  emit Unpaused(_msgSender());
              }
          }
          // SPDX-License-Identifier: MIT
          // 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);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
          pragma solidity ^0.8.20;
          import {IERC20} from "../IERC20.sol";
          /**
           * @dev Interface for the optional metadata functions from the ERC20 standard.
           */
          interface IERC20Metadata is IERC20 {
              /**
               * @dev Returns the name of the token.
               */
              function name() external view returns (string memory);
              /**
               * @dev Returns the symbol of the token.
               */
              function symbol() external view returns (string memory);
              /**
               * @dev Returns the decimals places of the token.
               */
              function decimals() external view returns (uint8);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Standard ERC20 Errors
           * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
           */
          interface IERC20Errors {
              /**
               * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               * @param balance Current balance for the interacting account.
               * @param needed Minimum amount required to perform a transfer.
               */
              error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
              /**
               * @dev Indicates a failure with the token `sender`. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               */
              error ERC20InvalidSender(address sender);
              /**
               * @dev Indicates a failure with the token `receiver`. Used in transfers.
               * @param receiver Address to which tokens are being transferred.
               */
              error ERC20InvalidReceiver(address receiver);
              /**
               * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
               * @param spender Address that may be allowed to operate on tokens without being their owner.
               * @param allowance Amount of tokens a `spender` is allowed to operate with.
               * @param needed Minimum amount required to perform a transfer.
               */
              error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
              /**
               * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
               * @param approver Address initiating an approval operation.
               */
              error ERC20InvalidApprover(address approver);
              /**
               * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
               * @param spender Address that may be allowed to operate on tokens without being their owner.
               */
              error ERC20InvalidSpender(address spender);
          }
          /**
           * @dev Standard ERC721 Errors
           * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
           */
          interface IERC721Errors {
              /**
               * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
               * Used in balance queries.
               * @param owner Address of the current owner of a token.
               */
              error ERC721InvalidOwner(address owner);
              /**
               * @dev Indicates a `tokenId` whose `owner` is the zero address.
               * @param tokenId Identifier number of a token.
               */
              error ERC721NonexistentToken(uint256 tokenId);
              /**
               * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               * @param tokenId Identifier number of a token.
               * @param owner Address of the current owner of a token.
               */
              error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
              /**
               * @dev Indicates a failure with the token `sender`. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               */
              error ERC721InvalidSender(address sender);
              /**
               * @dev Indicates a failure with the token `receiver`. Used in transfers.
               * @param receiver Address to which tokens are being transferred.
               */
              error ERC721InvalidReceiver(address receiver);
              /**
               * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
               * @param operator Address that may be allowed to operate on tokens without being their owner.
               * @param tokenId Identifier number of a token.
               */
              error ERC721InsufficientApproval(address operator, uint256 tokenId);
              /**
               * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
               * @param approver Address initiating an approval operation.
               */
              error ERC721InvalidApprover(address approver);
              /**
               * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
               * @param operator Address that may be allowed to operate on tokens without being their owner.
               */
              error ERC721InvalidOperator(address operator);
          }
          /**
           * @dev Standard ERC1155 Errors
           * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
           */
          interface IERC1155Errors {
              /**
               * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               * @param balance Current balance for the interacting account.
               * @param needed Minimum amount required to perform a transfer.
               * @param tokenId Identifier number of a token.
               */
              error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
              /**
               * @dev Indicates a failure with the token `sender`. Used in transfers.
               * @param sender Address whose tokens are being transferred.
               */
              error ERC1155InvalidSender(address sender);
              /**
               * @dev Indicates a failure with the token `receiver`. Used in transfers.
               * @param receiver Address to which tokens are being transferred.
               */
              error ERC1155InvalidReceiver(address receiver);
              /**
               * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
               * @param operator Address that may be allowed to operate on tokens without being their owner.
               * @param owner Address of the current owner of a token.
               */
              error ERC1155MissingApprovalForAll(address operator, address owner);
              /**
               * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
               * @param approver Address initiating an approval operation.
               */
              error ERC1155InvalidApprover(address approver);
              /**
               * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
               * @param operator Address that may be allowed to operate on tokens without being their owner.
               */
              error ERC1155InvalidOperator(address operator);
              /**
               * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
               * Used in batch transfers.
               * @param idsLength Length of the array of token identifiers
               * @param valuesLength Length of the array of token amounts
               */
              error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
          pragma solidity ^0.8.20;
          import {Strings} from "../Strings.sol";
          /**
           * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
           *
           * The library provides methods for generating a hash of a message that conforms to the
           * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
           * specifications.
           */
          library MessageHashUtils {
              /**
               * @dev Returns the keccak256 digest of an EIP-191 signed data with version
               * `0x45` (`personal_sign` messages).
               *
               * The digest is calculated by prefixing a bytes32 `messageHash` with
               * `"\\x19Ethereum Signed Message:\
          32"` and hashing the result. It corresponds with the
               * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
               *
               * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
               * keccak256, although any bytes32 value can be safely used because the final digest will
               * be re-hashed.
               *
               * See {ECDSA-recover}.
               */
              function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      mstore(0x00, "\\x19Ethereum Signed Message:\
          32") // 32 is the bytes-length of messageHash
                      mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
                      digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
                  }
              }
              /**
               * @dev Returns the keccak256 digest of an EIP-191 signed data with version
               * `0x45` (`personal_sign` messages).
               *
               * The digest is calculated by prefixing an arbitrary `message` with
               * `"\\x19Ethereum Signed Message:\
          " + len(message)` and hashing the result. It corresponds with the
               * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
               *
               * See {ECDSA-recover}.
               */
              function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
                  return
                      keccak256(bytes.concat("\\x19Ethereum Signed Message:\
          ", bytes(Strings.toString(message.length)), message));
              }
              /**
               * @dev Returns the keccak256 digest of an EIP-191 signed data with version
               * `0x00` (data with intended validator).
               *
               * The digest is calculated by prefixing an arbitrary `data` with `"\\x19\\x00"` and the intended
               * `validator` address. Then hashing the result.
               *
               * See {ECDSA-recover}.
               */
              function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
                  return keccak256(abi.encodePacked(hex"19_00", validator, data));
              }
              /**
               * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
               *
               * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
               * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the
               * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
               *
               * See {ECDSA-recover}.
               */
              function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      let ptr := mload(0x40)
                      mstore(ptr, hex"19_01")
                      mstore(add(ptr, 0x02), domainSeparator)
                      mstore(add(ptr, 0x22), structHash)
                      digest := keccak256(ptr, 0x42)
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
          pragma solidity ^0.8.20;
          import {StorageSlot} from "./StorageSlot.sol";
          // | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
          // | length  | 0x                                                              BB |
          type ShortString is bytes32;
          /**
           * @dev This library provides functions to convert short memory strings
           * into a `ShortString` type that can be used as an immutable variable.
           *
           * Strings of arbitrary length can be optimized using this library if
           * they are short enough (up to 31 bytes) by packing them with their
           * length (1 byte) in a single EVM word (32 bytes). Additionally, a
           * fallback mechanism can be used for every other case.
           *
           * Usage example:
           *
           * ```solidity
           * contract Named {
           *     using ShortStrings for *;
           *
           *     ShortString private immutable _name;
           *     string private _nameFallback;
           *
           *     constructor(string memory contractName) {
           *         _name = contractName.toShortStringWithFallback(_nameFallback);
           *     }
           *
           *     function name() external view returns (string memory) {
           *         return _name.toStringWithFallback(_nameFallback);
           *     }
           * }
           * ```
           */
          library ShortStrings {
              // Used as an identifier for strings longer than 31 bytes.
              bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
              error StringTooLong(string str);
              error InvalidShortString();
              /**
               * @dev Encode a string of at most 31 chars into a `ShortString`.
               *
               * This will trigger a `StringTooLong` error is the input string is too long.
               */
              function toShortString(string memory str) internal pure returns (ShortString) {
                  bytes memory bstr = bytes(str);
                  if (bstr.length > 31) {
                      revert StringTooLong(str);
                  }
                  return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
              }
              /**
               * @dev Decode a `ShortString` back to a "normal" string.
               */
              function toString(ShortString sstr) internal pure returns (string memory) {
                  uint256 len = byteLength(sstr);
                  // using `new string(len)` would work locally but is not memory safe.
                  string memory str = new string(32);
                  /// @solidity memory-safe-assembly
                  assembly {
                      mstore(str, len)
                      mstore(add(str, 0x20), sstr)
                  }
                  return str;
              }
              /**
               * @dev Return the length of a `ShortString`.
               */
              function byteLength(ShortString sstr) internal pure returns (uint256) {
                  uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
                  if (result > 31) {
                      revert InvalidShortString();
                  }
                  return result;
              }
              /**
               * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
               */
              function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
                  if (bytes(value).length < 32) {
                      return toShortString(value);
                  } else {
                      StorageSlot.getStringSlot(store).value = value;
                      return ShortString.wrap(FALLBACK_SENTINEL);
                  }
              }
              /**
               * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
               */
              function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
                  if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
                      return toString(value);
                  } else {
                      return store;
                  }
              }
              /**
               * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
               * {setWithFallback}.
               *
               * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
               * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
               */
              function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
                  if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
                      return byteLength(value);
                  } else {
                      return bytes(store).length;
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
          pragma solidity ^0.8.20;
          interface IERC5267 {
              /**
               * @dev MAY be emitted to signal that the domain could have changed.
               */
              event EIP712DomainChanged();
              /**
               * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
               * signature.
               */
              function eip712Domain()
                  external
                  view
                  returns (
                      bytes1 fields,
                      string memory name,
                      string memory version,
                      uint256 chainId,
                      address verifyingContract,
                      bytes32 salt,
                      uint256[] memory extensions
                  );
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
          pragma solidity ^0.8.20;
          import {Math} from "./math/Math.sol";
          import {SignedMath} from "./math/SignedMath.sol";
          /**
           * @dev String operations.
           */
          library Strings {
              bytes16 private constant HEX_DIGITS = "0123456789abcdef";
              uint8 private constant ADDRESS_LENGTH = 20;
              /**
               * @dev The `value` string doesn't fit in the specified `length`.
               */
              error StringsInsufficientHexLength(uint256 value, uint256 length);
              /**
               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  unchecked {
                      uint256 length = Math.log10(value) + 1;
                      string memory buffer = new string(length);
                      uint256 ptr;
                      /// @solidity memory-safe-assembly
                      assembly {
                          ptr := add(buffer, add(32, length))
                      }
                      while (true) {
                          ptr--;
                          /// @solidity memory-safe-assembly
                          assembly {
                              mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                          }
                          value /= 10;
                          if (value == 0) break;
                      }
                      return buffer;
                  }
              }
              /**
               * @dev Converts a `int256` to its ASCII `string` decimal representation.
               */
              function toStringSigned(int256 value) internal pure returns (string memory) {
                  return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
               */
              function toHexString(uint256 value) internal pure returns (string memory) {
                  unchecked {
                      return toHexString(value, Math.log256(value) + 1);
                  }
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
               */
              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                  uint256 localValue = value;
                  bytes memory buffer = new bytes(2 * length + 2);
                  buffer[0] = "0";
                  buffer[1] = "x";
                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                      buffer[i] = HEX_DIGITS[localValue & 0xf];
                      localValue >>= 4;
                  }
                  if (localValue != 0) {
                      revert StringsInsufficientHexLength(value, length);
                  }
                  return string(buffer);
              }
              /**
               * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
               * representation.
               */
              function toHexString(address addr) internal pure returns (string memory) {
                  return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
              }
              /**
               * @dev Returns true if the two strings are equal.
               */
              function equal(string memory a, string memory b) internal pure returns (bool) {
                  return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
          // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
          pragma solidity ^0.8.20;
          /**
           * @dev Library for reading and writing primitive types to specific storage slots.
           *
           * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
           * This library helps with reading and writing to such slots without the need for inline assembly.
           *
           * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
           *
           * Example usage to set ERC1967 implementation slot:
           * ```solidity
           * contract ERC1967 {
           *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
           *
           *     function _getImplementation() internal view returns (address) {
           *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
           *     }
           *
           *     function _setImplementation(address newImplementation) internal {
           *         require(newImplementation.code.length > 0);
           *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
           *     }
           * }
           * ```
           */
          library StorageSlot {
              struct AddressSlot {
                  address value;
              }
              struct BooleanSlot {
                  bool value;
              }
              struct Bytes32Slot {
                  bytes32 value;
              }
              struct Uint256Slot {
                  uint256 value;
              }
              struct StringSlot {
                  string value;
              }
              struct BytesSlot {
                  bytes value;
              }
              /**
               * @dev Returns an `AddressSlot` with member `value` located at `slot`.
               */
              function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
               */
              function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
               */
              function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
               */
              function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `StringSlot` with member `value` located at `slot`.
               */
              function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
               */
              function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := store.slot
                  }
              }
              /**
               * @dev Returns an `BytesSlot` with member `value` located at `slot`.
               */
              function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := slot
                  }
              }
              /**
               * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
               */
              function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
                  /// @solidity memory-safe-assembly
                  assembly {
                      r.slot := store.slot
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Standard math utilities missing in the Solidity language.
           */
          library Math {
              /**
               * @dev Muldiv operation overflow.
               */
              error MathOverflowedMulDiv();
              enum Rounding {
                  Floor, // Toward negative infinity
                  Ceil, // Toward positive infinity
                  Trunc, // Toward zero
                  Expand // Away from zero
              }
              /**
               * @dev Returns the addition of two unsigned integers, with an overflow flag.
               */
              function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  unchecked {
                      uint256 c = a + b;
                      if (c < a) return (false, 0);
                      return (true, c);
                  }
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
               */
              function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  unchecked {
                      if (b > a) return (false, 0);
                      return (true, a - b);
                  }
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
               */
              function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  unchecked {
                      // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                      // benefit is lost if 'b' is also tested.
                      // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                      if (a == 0) return (true, 0);
                      uint256 c = a * b;
                      if (c / a != b) return (false, 0);
                      return (true, c);
                  }
              }
              /**
               * @dev Returns the division of two unsigned integers, with a division by zero flag.
               */
              function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  unchecked {
                      if (b == 0) return (false, 0);
                      return (true, a / b);
                  }
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
               */
              function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  unchecked {
                      if (b == 0) return (false, 0);
                      return (true, a % b);
                  }
              }
              /**
               * @dev Returns the largest of two numbers.
               */
              function max(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a > b ? a : b;
              }
              /**
               * @dev Returns the smallest of two numbers.
               */
              function min(uint256 a, uint256 b) internal pure returns (uint256) {
                  return a < b ? a : b;
              }
              /**
               * @dev Returns the average of two numbers. The result is rounded towards
               * zero.
               */
              function average(uint256 a, uint256 b) internal pure returns (uint256) {
                  // (a + b) / 2 can overflow.
                  return (a & b) + (a ^ b) / 2;
              }
              /**
               * @dev Returns the ceiling of the division of two numbers.
               *
               * This differs from standard division with `/` in that it rounds towards infinity instead
               * of rounding towards zero.
               */
              function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (b == 0) {
                      // Guarantee the same behavior as in a regular Solidity division.
                      return a / b;
                  }
                  // (a + b - 1) / b can overflow on addition, so we distribute.
                  return a == 0 ? 0 : (a - 1) / b + 1;
              }
              /**
               * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
               * denominator == 0.
               * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
               * Uniswap Labs also under MIT license.
               */
              function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
                  unchecked {
                      // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                      // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                      // variables such that product = prod1 * 2^256 + prod0.
                      uint256 prod0 = x * y; // Least significant 256 bits of the product
                      uint256 prod1; // Most significant 256 bits of the product
                      assembly {
                          let mm := mulmod(x, y, not(0))
                          prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                      }
                      // Handle non-overflow cases, 256 by 256 division.
                      if (prod1 == 0) {
                          // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                          // The surrounding unchecked block does not change this fact.
                          // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                          return prod0 / denominator;
                      }
                      // Make sure the result is less than 2^256. Also prevents denominator == 0.
                      if (denominator <= prod1) {
                          revert MathOverflowedMulDiv();
                      }
                      ///////////////////////////////////////////////
                      // 512 by 256 division.
                      ///////////////////////////////////////////////
                      // Make division exact by subtracting the remainder from [prod1 prod0].
                      uint256 remainder;
                      assembly {
                          // Compute remainder using mulmod.
                          remainder := mulmod(x, y, denominator)
                          // Subtract 256 bit number from 512 bit number.
                          prod1 := sub(prod1, gt(remainder, prod0))
                          prod0 := sub(prod0, remainder)
                      }
                      // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
                      // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
                      uint256 twos = denominator & (0 - denominator);
                      assembly {
                          // Divide denominator by twos.
                          denominator := div(denominator, twos)
                          // Divide [prod1 prod0] by twos.
                          prod0 := div(prod0, twos)
                          // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                          twos := add(div(sub(0, twos), twos), 1)
                      }
                      // Shift in bits from prod1 into prod0.
                      prod0 |= prod1 * twos;
                      // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                      // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                      // four bits. That is, denominator * inv = 1 mod 2^4.
                      uint256 inverse = (3 * denominator) ^ 2;
                      // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
                      // works in modular arithmetic, doubling the correct bits in each step.
                      inverse *= 2 - denominator * inverse; // inverse mod 2^8
                      inverse *= 2 - denominator * inverse; // inverse mod 2^16
                      inverse *= 2 - denominator * inverse; // inverse mod 2^32
                      inverse *= 2 - denominator * inverse; // inverse mod 2^64
                      inverse *= 2 - denominator * inverse; // inverse mod 2^128
                      inverse *= 2 - denominator * inverse; // inverse mod 2^256
                      // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                      // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                      // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                      // is no longer required.
                      result = prod0 * inverse;
                      return result;
                  }
              }
              /**
               * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
               */
              function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
                  uint256 result = mulDiv(x, y, denominator);
                  if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
                      result += 1;
                  }
                  return result;
              }
              /**
               * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
               * towards zero.
               *
               * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
               */
              function sqrt(uint256 a) internal pure returns (uint256) {
                  if (a == 0) {
                      return 0;
                  }
                  // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
                  //
                  // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
                  // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
                  //
                  // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
                  // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
                  // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
                  //
                  // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
                  uint256 result = 1 << (log2(a) >> 1);
                  // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
                  // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
                  // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
                  // into the expected uint128 result.
                  unchecked {
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      result = (result + a / result) >> 1;
                      return min(result, a / result);
                  }
              }
              /**
               * @notice Calculates sqrt(a), following the selected rounding direction.
               */
              function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
                  unchecked {
                      uint256 result = sqrt(a);
                      return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
                  }
              }
              /**
               * @dev Return the log in base 2 of a positive value rounded towards zero.
               * Returns 0 if given 0.
               */
              function log2(uint256 value) internal pure returns (uint256) {
                  uint256 result = 0;
                  unchecked {
                      if (value >> 128 > 0) {
                          value >>= 128;
                          result += 128;
                      }
                      if (value >> 64 > 0) {
                          value >>= 64;
                          result += 64;
                      }
                      if (value >> 32 > 0) {
                          value >>= 32;
                          result += 32;
                      }
                      if (value >> 16 > 0) {
                          value >>= 16;
                          result += 16;
                      }
                      if (value >> 8 > 0) {
                          value >>= 8;
                          result += 8;
                      }
                      if (value >> 4 > 0) {
                          value >>= 4;
                          result += 4;
                      }
                      if (value >> 2 > 0) {
                          value >>= 2;
                          result += 2;
                      }
                      if (value >> 1 > 0) {
                          result += 1;
                      }
                  }
                  return result;
              }
              /**
               * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
               * Returns 0 if given 0.
               */
              function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
                  unchecked {
                      uint256 result = log2(value);
                      return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
                  }
              }
              /**
               * @dev Return the log in base 10 of a positive value rounded towards zero.
               * Returns 0 if given 0.
               */
              function log10(uint256 value) internal pure returns (uint256) {
                  uint256 result = 0;
                  unchecked {
                      if (value >= 10 ** 64) {
                          value /= 10 ** 64;
                          result += 64;
                      }
                      if (value >= 10 ** 32) {
                          value /= 10 ** 32;
                          result += 32;
                      }
                      if (value >= 10 ** 16) {
                          value /= 10 ** 16;
                          result += 16;
                      }
                      if (value >= 10 ** 8) {
                          value /= 10 ** 8;
                          result += 8;
                      }
                      if (value >= 10 ** 4) {
                          value /= 10 ** 4;
                          result += 4;
                      }
                      if (value >= 10 ** 2) {
                          value /= 10 ** 2;
                          result += 2;
                      }
                      if (value >= 10 ** 1) {
                          result += 1;
                      }
                  }
                  return result;
              }
              /**
               * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
               * Returns 0 if given 0.
               */
              function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
                  unchecked {
                      uint256 result = log10(value);
                      return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
                  }
              }
              /**
               * @dev Return the log in base 256 of a positive value rounded towards zero.
               * Returns 0 if given 0.
               *
               * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
               */
              function log256(uint256 value) internal pure returns (uint256) {
                  uint256 result = 0;
                  unchecked {
                      if (value >> 128 > 0) {
                          value >>= 128;
                          result += 16;
                      }
                      if (value >> 64 > 0) {
                          value >>= 64;
                          result += 8;
                      }
                      if (value >> 32 > 0) {
                          value >>= 32;
                          result += 4;
                      }
                      if (value >> 16 > 0) {
                          value >>= 16;
                          result += 2;
                      }
                      if (value >> 8 > 0) {
                          result += 1;
                      }
                  }
                  return result;
              }
              /**
               * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
               * Returns 0 if given 0.
               */
              function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
                  unchecked {
                      uint256 result = log256(value);
                      return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
                  }
              }
              /**
               * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
               */
              function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
                  return uint8(rounding) % 2 == 1;
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
          pragma solidity ^0.8.20;
          /**
           * @dev Standard signed math utilities missing in the Solidity language.
           */
          library SignedMath {
              /**
               * @dev Returns the largest of two signed numbers.
               */
              function max(int256 a, int256 b) internal pure returns (int256) {
                  return a > b ? a : b;
              }
              /**
               * @dev Returns the smallest of two signed numbers.
               */
              function min(int256 a, int256 b) internal pure returns (int256) {
                  return a < b ? a : b;
              }
              /**
               * @dev Returns the average of two signed numbers without overflow.
               * The result is rounded towards zero.
               */
              function average(int256 a, int256 b) internal pure returns (int256) {
                  // Formula from the book "Hacker's Delight"
                  int256 x = (a & b) + ((a ^ b) >> 1);
                  return x + (int256(uint256(x) >> 255) & (a ^ b));
              }
              /**
               * @dev Returns the absolute unsigned value of a signed value.
               */
              function abs(int256 n) internal pure returns (uint256) {
                  unchecked {
                      // must be unchecked in order to support `n = type(int256).min`
                      return uint256(n >= 0 ? n : -n);
                  }
              }
          }
          

          File 4 of 6: TetherToken
          pragma solidity ^0.4.17;
          
          /**
           * @title SafeMath
           * @dev Math operations with safety checks that throw on error
           */
          library SafeMath {
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) {
                      return 0;
                  }
                  uint256 c = a * b;
                  assert(c / a == b);
                  return c;
              }
          
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  // assert(b > 0); // Solidity automatically throws when dividing by 0
                  uint256 c = a / b;
                  // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                  return c;
              }
          
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  assert(b <= a);
                  return a - b;
              }
          
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  assert(c >= a);
                  return c;
              }
          }
          
          /**
           * @title Ownable
           * @dev The Ownable contract has an owner address, and provides basic authorization control
           * functions, this simplifies the implementation of "user permissions".
           */
          contract Ownable {
              address public owner;
          
              /**
                * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                * account.
                */
              function Ownable() public {
                  owner = msg.sender;
              }
          
              /**
                * @dev Throws if called by any account other than the owner.
                */
              modifier onlyOwner() {
                  require(msg.sender == owner);
                  _;
              }
          
              /**
              * @dev Allows the current owner to transfer control of the contract to a newOwner.
              * @param newOwner The address to transfer ownership to.
              */
              function transferOwnership(address newOwner) public onlyOwner {
                  if (newOwner != address(0)) {
                      owner = newOwner;
                  }
              }
          
          }
          
          /**
           * @title ERC20Basic
           * @dev Simpler version of ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/20
           */
          contract ERC20Basic {
              uint public _totalSupply;
              function totalSupply() public constant returns (uint);
              function balanceOf(address who) public constant returns (uint);
              function transfer(address to, uint value) public;
              event Transfer(address indexed from, address indexed to, uint value);
          }
          
          /**
           * @title ERC20 interface
           * @dev see https://github.com/ethereum/EIPs/issues/20
           */
          contract ERC20 is ERC20Basic {
              function allowance(address owner, address spender) public constant returns (uint);
              function transferFrom(address from, address to, uint value) public;
              function approve(address spender, uint value) public;
              event Approval(address indexed owner, address indexed spender, uint value);
          }
          
          /**
           * @title Basic token
           * @dev Basic version of StandardToken, with no allowances.
           */
          contract BasicToken is Ownable, ERC20Basic {
              using SafeMath for uint;
          
              mapping(address => uint) public balances;
          
              // additional variables for use if transaction fees ever became necessary
              uint public basisPointsRate = 0;
              uint public maximumFee = 0;
          
              /**
              * @dev Fix for the ERC20 short address attack.
              */
              modifier onlyPayloadSize(uint size) {
                  require(!(msg.data.length < size + 4));
                  _;
              }
          
              /**
              * @dev transfer token for a specified address
              * @param _to The address to transfer to.
              * @param _value The amount to be transferred.
              */
              function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                  uint fee = (_value.mul(basisPointsRate)).div(10000);
                  if (fee > maximumFee) {
                      fee = maximumFee;
                  }
                  uint sendAmount = _value.sub(fee);
                  balances[msg.sender] = balances[msg.sender].sub(_value);
                  balances[_to] = balances[_to].add(sendAmount);
                  if (fee > 0) {
                      balances[owner] = balances[owner].add(fee);
                      Transfer(msg.sender, owner, fee);
                  }
                  Transfer(msg.sender, _to, sendAmount);
              }
          
              /**
              * @dev Gets the balance of the specified address.
              * @param _owner The address to query the the balance of.
              * @return An uint representing the amount owned by the passed address.
              */
              function balanceOf(address _owner) public constant returns (uint balance) {
                  return balances[_owner];
              }
          
          }
          
          /**
           * @title Standard ERC20 token
           *
           * @dev Implementation of the basic standard token.
           * @dev https://github.com/ethereum/EIPs/issues/20
           * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
           */
          contract StandardToken is BasicToken, ERC20 {
          
              mapping (address => mapping (address => uint)) public allowed;
          
              uint public constant MAX_UINT = 2**256 - 1;
          
              /**
              * @dev Transfer tokens from one address to another
              * @param _from address The address which you want to send tokens from
              * @param _to address The address which you want to transfer to
              * @param _value uint the amount of tokens to be transferred
              */
              function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                  var _allowance = allowed[_from][msg.sender];
          
                  // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                  // if (_value > _allowance) throw;
          
                  uint fee = (_value.mul(basisPointsRate)).div(10000);
                  if (fee > maximumFee) {
                      fee = maximumFee;
                  }
                  if (_allowance < MAX_UINT) {
                      allowed[_from][msg.sender] = _allowance.sub(_value);
                  }
                  uint sendAmount = _value.sub(fee);
                  balances[_from] = balances[_from].sub(_value);
                  balances[_to] = balances[_to].add(sendAmount);
                  if (fee > 0) {
                      balances[owner] = balances[owner].add(fee);
                      Transfer(_from, owner, fee);
                  }
                  Transfer(_from, _to, sendAmount);
              }
          
              /**
              * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
              * @param _spender The address which will spend the funds.
              * @param _value The amount of tokens to be spent.
              */
              function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
          
                  // To change the approve amount you first have to reduce the addresses`
                  //  allowance to zero by calling `approve(_spender, 0)` if it is not
                  //  already 0 to mitigate the race condition described here:
                  //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                  require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
          
                  allowed[msg.sender][_spender] = _value;
                  Approval(msg.sender, _spender, _value);
              }
          
              /**
              * @dev Function to check the amount of tokens than an owner allowed to a spender.
              * @param _owner address The address which owns the funds.
              * @param _spender address The address which will spend the funds.
              * @return A uint specifying the amount of tokens still available for the spender.
              */
              function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                  return allowed[_owner][_spender];
              }
          
          }
          
          
          /**
           * @title Pausable
           * @dev Base contract which allows children to implement an emergency stop mechanism.
           */
          contract Pausable is Ownable {
            event Pause();
            event Unpause();
          
            bool public paused = false;
          
          
            /**
             * @dev Modifier to make a function callable only when the contract is not paused.
             */
            modifier whenNotPaused() {
              require(!paused);
              _;
            }
          
            /**
             * @dev Modifier to make a function callable only when the contract is paused.
             */
            modifier whenPaused() {
              require(paused);
              _;
            }
          
            /**
             * @dev called by the owner to pause, triggers stopped state
             */
            function pause() onlyOwner whenNotPaused public {
              paused = true;
              Pause();
            }
          
            /**
             * @dev called by the owner to unpause, returns to normal state
             */
            function unpause() onlyOwner whenPaused public {
              paused = false;
              Unpause();
            }
          }
          
          contract BlackList is Ownable, BasicToken {
          
              /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
              function getBlackListStatus(address _maker) external constant returns (bool) {
                  return isBlackListed[_maker];
              }
          
              function getOwner() external constant returns (address) {
                  return owner;
              }
          
              mapping (address => bool) public isBlackListed;
              
              function addBlackList (address _evilUser) public onlyOwner {
                  isBlackListed[_evilUser] = true;
                  AddedBlackList(_evilUser);
              }
          
              function removeBlackList (address _clearedUser) public onlyOwner {
                  isBlackListed[_clearedUser] = false;
                  RemovedBlackList(_clearedUser);
              }
          
              function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                  require(isBlackListed[_blackListedUser]);
                  uint dirtyFunds = balanceOf(_blackListedUser);
                  balances[_blackListedUser] = 0;
                  _totalSupply -= dirtyFunds;
                  DestroyedBlackFunds(_blackListedUser, dirtyFunds);
              }
          
              event DestroyedBlackFunds(address _blackListedUser, uint _balance);
          
              event AddedBlackList(address _user);
          
              event RemovedBlackList(address _user);
          
          }
          
          contract UpgradedStandardToken is StandardToken{
              // those methods are called by the legacy contract
              // and they must ensure msg.sender to be the contract address
              function transferByLegacy(address from, address to, uint value) public;
              function transferFromByLegacy(address sender, address from, address spender, uint value) public;
              function approveByLegacy(address from, address spender, uint value) public;
          }
          
          contract TetherToken is Pausable, StandardToken, BlackList {
          
              string public name;
              string public symbol;
              uint public decimals;
              address public upgradedAddress;
              bool public deprecated;
          
              //  The contract can be initialized with a number of tokens
              //  All the tokens are deposited to the owner address
              //
              // @param _balance Initial supply of the contract
              // @param _name Token Name
              // @param _symbol Token symbol
              // @param _decimals Token decimals
              function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                  _totalSupply = _initialSupply;
                  name = _name;
                  symbol = _symbol;
                  decimals = _decimals;
                  balances[owner] = _initialSupply;
                  deprecated = false;
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function transfer(address _to, uint _value) public whenNotPaused {
                  require(!isBlackListed[msg.sender]);
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                  } else {
                      return super.transfer(_to, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                  require(!isBlackListed[_from]);
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                  } else {
                      return super.transferFrom(_from, _to, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function balanceOf(address who) public constant returns (uint) {
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                  } else {
                      return super.balanceOf(who);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                  if (deprecated) {
                      return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                  } else {
                      return super.approve(_spender, _value);
                  }
              }
          
              // Forward ERC20 methods to upgraded contract if this one is deprecated
              function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                  if (deprecated) {
                      return StandardToken(upgradedAddress).allowance(_owner, _spender);
                  } else {
                      return super.allowance(_owner, _spender);
                  }
              }
          
              // deprecate current contract in favour of a new one
              function deprecate(address _upgradedAddress) public onlyOwner {
                  deprecated = true;
                  upgradedAddress = _upgradedAddress;
                  Deprecate(_upgradedAddress);
              }
          
              // deprecate current contract if favour of a new one
              function totalSupply() public constant returns (uint) {
                  if (deprecated) {
                      return StandardToken(upgradedAddress).totalSupply();
                  } else {
                      return _totalSupply;
                  }
              }
          
              // Issue a new amount of tokens
              // these tokens are deposited into the owner address
              //
              // @param _amount Number of tokens to be issued
              function issue(uint amount) public onlyOwner {
                  require(_totalSupply + amount > _totalSupply);
                  require(balances[owner] + amount > balances[owner]);
          
                  balances[owner] += amount;
                  _totalSupply += amount;
                  Issue(amount);
              }
          
              // Redeem tokens.
              // These tokens are withdrawn from the owner address
              // if the balance must be enough to cover the redeem
              // or the call will fail.
              // @param _amount Number of tokens to be issued
              function redeem(uint amount) public onlyOwner {
                  require(_totalSupply >= amount);
                  require(balances[owner] >= amount);
          
                  _totalSupply -= amount;
                  balances[owner] -= amount;
                  Redeem(amount);
              }
          
              function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                  // Ensure transparency by hardcoding limit beyond which fees can never be added
                  require(newBasisPoints < 20);
                  require(newMaxFee < 50);
          
                  basisPointsRate = newBasisPoints;
                  maximumFee = newMaxFee.mul(10**decimals);
          
                  Params(basisPointsRate, maximumFee);
              }
          
              // Called when new token are issued
              event Issue(uint amount);
          
              // Called when tokens are redeemed
              event Redeem(uint amount);
          
              // Called when contract is deprecated
              event Deprecate(address newAddress);
          
              // Called if contract ever adds fees
              event Params(uint feeBasisPoints, uint maxFee);
          }

          File 5 of 6: TokenChwomper
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
          pragma solidity >= 0.8.0;
          /**
           * @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 amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `to`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address to, uint256 amount) external returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender) external view returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `from` to `to` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 amount) external returns (bool);
          }// SPDX-License-Identifier: UNLICENSED
          pragma solidity >= 0.8.0;
          interface IRedSnwapper {
              struct InputToken {
                  address token;
                  uint256 amountIn;
                  address transferTo;
              }
              struct OutputToken {
                  address token;
                  address recipient;
                  uint256 amountOutMin;
              }
              struct Executor {
                  address executor;
                  uint256 value;
                  bytes data;
              }
              function snwap(
                  address tokenIn,
                  uint256 amountIn,
                  address recipient,
                  address tokenOut,
                  uint256 amountOutMin,
                  address executor,
                  bytes calldata executorData
              ) external returns (uint256 amountOut);
              function snwapMultiple(
                  InputToken[] calldata inputTokens,
                  OutputToken[] calldata outputTokens,
                  Executor[] calldata executors
              ) external returns (uint256[] memory amountOut);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
          pragma solidity ^0.8.0;
          import "../utils/Context.sol";
          /**
           * @dev Contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * By default, the owner account will be the one that deploys the contract. This
           * can later be changed with {transferOwnership}.
           *
           * This module is used through inheritance. It will make available the modifier
           * `onlyOwner`, which can be applied to your functions to restrict their use to
           * the owner.
           */
          abstract contract Ownable is Context {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              constructor() {
                  _transferOwnership(_msgSender());
              }
              /**
               * @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 {
                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
              }
              /**
               * @dev Leaves the contract without owner. It will not be possible to call
               * `onlyOwner` functions anymore. Can only be called by the current owner.
               *
               * NOTE: Renouncing ownership will leave the contract without an owner,
               * thereby removing any functionality that is only available to the owner.
               */
              function renounceOwnership() public virtual onlyOwner {
                  _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 {
                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)
          pragma solidity ^0.8.0;
          import "./Ownable.sol";
          /**
           * @dev Contract module which provides access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * By default, the owner account will be the one that deploys the contract. This
           * can later be changed with {transferOwnership} and {acceptOwnership}.
           *
           * This module is used through inheritance. It will make available all functions
           * from parent (Ownable).
           */
          abstract contract Ownable2Step is Ownable {
              address private _pendingOwner;
              event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Returns the address of the pending owner.
               */
              function pendingOwner() public view virtual returns (address) {
                  return _pendingOwner;
              }
              /**
               * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
               * Can only be called by the current owner.
               */
              function transferOwnership(address newOwner) public virtual override onlyOwner {
                  _pendingOwner = newOwner;
                  emit OwnershipTransferStarted(owner(), newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual override {
                  delete _pendingOwner;
                  super._transferOwnership(newOwner);
              }
              /**
               * @dev The new owner accepts the ownership transfer.
               */
              function acceptOwnership() external {
                  address sender = _msgSender();
                  require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                  _transferOwnership(sender);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity >=0.8.0;
          import "openzeppelin/access/Ownable2Step.sol";
          abstract contract Auth is Ownable2Step {
              event SetTrusted(address indexed user, bool isTrusted);
              mapping(address => bool) public trusted;
              error OnlyTrusted();
              modifier onlyTrusted() {
                  if (!trusted[msg.sender]) revert OnlyTrusted();
                  _;
              }
              constructor(address trustedUser) {
                  trusted[trustedUser] = true;
                  emit SetTrusted(trustedUser, true);
              }
              function setTrusted(address user, bool isTrusted) external onlyOwner {
                  trusted[user] = isTrusted;
                  emit SetTrusted(user, isTrusted);
              }
          }// SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity >=0.8.0;
          import "interfaces/IRedSnwapper.sol";
          import "interfaces/IERC20.sol";
          import "./Auth.sol";
          /// @title TokenChwomper for selling accumulated tokens for weth or other base assets
          /// @notice This contract will be used for fee collection and breakdown
          /// @dev Uses Auth contract for 2-step owner process and trust operators to guard functions
          contract TokenChwomper is Auth {
            address public immutable weth;
            IRedSnwapper public redSnwapper;
            bytes4 private constant TRANSFER_SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
            error TransferFailed();
            constructor(
              address _operator,
              address _redSnwapper,
              address _weth
            ) Auth(_operator) {
              // initial owner is msg.sender
              redSnwapper = IRedSnwapper(_redSnwapper);
              weth = _weth;
            }
            /// @notice Updates the RedSnwapper to be used for swapping tokens
            /// @dev make sure new RedSnwapper is backwards compatiable (should be)
            /// @param _redSnwapper The address of the new route processor
            function updateRedSnwapper(address _redSnwapper) external onlyOwner {
              redSnwapper = IRedSnwapper(_redSnwapper);
            }
            
            /// @notice Swaps tokens via the configured RedSnwapper
            /// @dev Must be called by a trusted operator
            /// @param tokenIn Address of the input token
            /// @param amountIn Amount of the input token to swap
            /// @param recipient Address to receive the output tokens
            /// @param tokenOut Address of the output token
            /// @param amountOutMin Minimum acceptable amount of output tokens (slippage protection)
            /// @param executor Address of the executor contract to perform the swap logic
            /// @param executorData Encoded data for the executor call
            /// @return amountOut The actual amount of output tokens received
            function snwap(
              address tokenIn,
              uint256 amountIn,
              address recipient,
              address tokenOut,
              uint256 amountOutMin,
              address executor,
              bytes calldata executorData
            ) external onlyTrusted returns (uint256 amountOut) {
               // Pre-fund RedSnwapper with input tokens
               _safeTransfer(tokenIn, address(redSnwapper), amountIn);
              // Execute snwap with zero amountIn
              amountOut = redSnwapper.snwap(
                tokenIn,
                0,
                recipient,
                tokenOut,
                amountOutMin,
                executor,
                executorData
              );
            }
            /// @notice Performs multiple swaps via the configured RedSnwapper
            /// @dev Must be called by a trusted operator
            /// @param inputTokens Array of input token parameters
            /// @param outputTokens Array of output token requirements
            /// @param executors Array of executor calls to perform
            /// @return amountOut Array of actual amounts of output tokens received
            function snwapMultiple(
              IRedSnwapper.InputToken[] calldata inputTokens,
              IRedSnwapper.OutputToken[] calldata outputTokens,
              IRedSnwapper.Executor[] calldata executors
            ) external onlyTrusted returns (uint256[] memory amountOut) {
             uint256 length = inputTokens.length;
              IRedSnwapper.InputToken[] memory _inputTokens = new IRedSnwapper.InputToken[](length);
              for (uint256 i = 0; i < length; ++i) {
                  // Pre-fund RedSnwapper with input tokens
                  _safeTransfer(
                      inputTokens[i].token,
                      address(redSnwapper),
                      inputTokens[i].amountIn
                  );
                  // Build _inputTokens with zero amountIn
                  _inputTokens[i] = IRedSnwapper.InputToken({
                      token: inputTokens[i].token,
                      amountIn: 0,
                      transferTo: inputTokens[i].transferTo
                  });
              }
              // Execute snwapMultiple
              amountOut = redSnwapper.snwapMultiple(
                  _inputTokens,
                  outputTokens,
                  executors
              );
            }
            /// @notice Withdraw any token or eth from the contract
            /// @dev can only be called by owner
            /// @param token The address of the token to be withdrawn, 0x0 for eth
            /// @param to The address to send the token to
            /// @param _value The amount of the token to be withdrawn
            function withdraw(address token, address to, uint256 _value) onlyOwner external {
              if (token != address(0)) {
                _safeTransfer(token, to, _value);
              } 
              else {
                (bool success, ) = to.call{value: _value}("");
                require(success);
              }
            }
            
            function _safeTransfer(address token, address to, uint value) internal {
              (bool success, bytes memory data) = token.call(abi.encodeWithSelector(TRANSFER_SELECTOR, to, value));
              if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferFailed();
            }
            /// @notice In case we receive any unwrapped eth (native token) we can call this
            /// @dev operators can call this 
            function wrapEth() onlyTrusted external {
              weth.call{value: address(this).balance}("");
            }
            /// @notice Available function in case we need to do any calls that aren't supported by the contract (unwinding lp positions, etc.)
            /// @dev can only be called by owner
            /// @param to The address to send the call to
            /// @param _value The amount of eth to send with the call
            /// @param data The data to be sent with the call
            function doAction(address to, uint256 _value, bytes memory data) onlyOwner external {
              (bool success, ) = to.call{value: _value}(data);
              require(success);
            }
            receive() external payable {}
          }

          File 6 of 6: TokenChwomper
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
          pragma solidity >= 0.8.0;
          /**
           * @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 amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `to`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address to, uint256 amount) external returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender) external view returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `from` to `to` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 amount) external returns (bool);
          }// SPDX-License-Identifier: UNLICENSED
          pragma solidity >= 0.8.0;
          interface IRedSnwapper {
              struct InputToken {
                  address token;
                  uint256 amountIn;
                  address transferTo;
              }
              struct OutputToken {
                  address token;
                  address recipient;
                  uint256 amountOutMin;
              }
              struct Executor {
                  address executor;
                  uint256 value;
                  bytes data;
              }
              function snwap(
                  address tokenIn,
                  uint256 amountIn,
                  address recipient,
                  address tokenOut,
                  uint256 amountOutMin,
                  address executor,
                  bytes calldata executorData
              ) external returns (uint256 amountOut);
              function snwapMultiple(
                  InputToken[] calldata inputTokens,
                  OutputToken[] calldata outputTokens,
                  Executor[] calldata executors
              ) external returns (uint256[] memory amountOut);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
          pragma solidity ^0.8.0;
          import "../utils/Context.sol";
          /**
           * @dev Contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * By default, the owner account will be the one that deploys the contract. This
           * can later be changed with {transferOwnership}.
           *
           * This module is used through inheritance. It will make available the modifier
           * `onlyOwner`, which can be applied to your functions to restrict their use to
           * the owner.
           */
          abstract contract Ownable is Context {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              constructor() {
                  _transferOwnership(_msgSender());
              }
              /**
               * @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 {
                  require(owner() == _msgSender(), "Ownable: caller is not the owner");
              }
              /**
               * @dev Leaves the contract without owner. It will not be possible to call
               * `onlyOwner` functions anymore. Can only be called by the current owner.
               *
               * NOTE: Renouncing ownership will leave the contract without an owner,
               * thereby removing any functionality that is only available to the owner.
               */
              function renounceOwnership() public virtual onlyOwner {
                  _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 {
                  require(newOwner != address(0), "Ownable: new owner is the zero address");
                  _transferOwnership(newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`).
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual {
                  address oldOwner = _owner;
                  _owner = newOwner;
                  emit OwnershipTransferred(oldOwner, newOwner);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)
          pragma solidity ^0.8.0;
          import "./Ownable.sol";
          /**
           * @dev Contract module which provides access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * By default, the owner account will be the one that deploys the contract. This
           * can later be changed with {transferOwnership} and {acceptOwnership}.
           *
           * This module is used through inheritance. It will make available all functions
           * from parent (Ownable).
           */
          abstract contract Ownable2Step is Ownable {
              address private _pendingOwner;
              event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Returns the address of the pending owner.
               */
              function pendingOwner() public view virtual returns (address) {
                  return _pendingOwner;
              }
              /**
               * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
               * Can only be called by the current owner.
               */
              function transferOwnership(address newOwner) public virtual override onlyOwner {
                  _pendingOwner = newOwner;
                  emit OwnershipTransferStarted(owner(), newOwner);
              }
              /**
               * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
               * Internal function without access restriction.
               */
              function _transferOwnership(address newOwner) internal virtual override {
                  delete _pendingOwner;
                  super._transferOwnership(newOwner);
              }
              /**
               * @dev The new owner accepts the ownership transfer.
               */
              function acceptOwnership() external {
                  address sender = _msgSender();
                  require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
                  _transferOwnership(sender);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Provides information about the current execution context, including the
           * sender of the transaction and its data. While these are generally available
           * via msg.sender and msg.data, they should not be accessed in such a direct
           * manner, since when dealing with meta-transactions the account sending and
           * paying for execution may not be the actual sender (as far as an application
           * is concerned).
           *
           * This contract is only required for intermediate, library-like contracts.
           */
          abstract contract Context {
              function _msgSender() internal view virtual returns (address) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes calldata) {
                  return msg.data;
              }
          }
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity >=0.8.0;
          import "openzeppelin/access/Ownable2Step.sol";
          abstract contract Auth is Ownable2Step {
              event SetTrusted(address indexed user, bool isTrusted);
              mapping(address => bool) public trusted;
              error OnlyTrusted();
              modifier onlyTrusted() {
                  if (!trusted[msg.sender]) revert OnlyTrusted();
                  _;
              }
              constructor(address trustedUser) {
                  trusted[trustedUser] = true;
                  emit SetTrusted(trustedUser, true);
              }
              function setTrusted(address user, bool isTrusted) external onlyOwner {
                  trusted[user] = isTrusted;
                  emit SetTrusted(user, isTrusted);
              }
          }// SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity >=0.8.0;
          import "interfaces/IRedSnwapper.sol";
          import "interfaces/IERC20.sol";
          import "./Auth.sol";
          /// @title TokenChwomper for selling accumulated tokens for weth or other base assets
          /// @notice This contract will be used for fee collection and breakdown
          /// @dev Uses Auth contract for 2-step owner process and trust operators to guard functions
          contract TokenChwomper is Auth {
            address public immutable weth;
            IRedSnwapper public redSnwapper;
            bytes4 private constant TRANSFER_SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
            error TransferFailed();
            constructor(
              address _operator,
              address _redSnwapper,
              address _weth
            ) Auth(_operator) {
              // initial owner is msg.sender
              redSnwapper = IRedSnwapper(_redSnwapper);
              weth = _weth;
            }
            /// @notice Updates the RedSnwapper to be used for swapping tokens
            /// @dev make sure new RedSnwapper is backwards compatiable (should be)
            /// @param _redSnwapper The address of the new route processor
            function updateRedSnwapper(address _redSnwapper) external onlyOwner {
              redSnwapper = IRedSnwapper(_redSnwapper);
            }
            
            /// @notice Swaps tokens via the configured RedSnwapper
            /// @dev Must be called by a trusted operator
            /// @param tokenIn Address of the input token
            /// @param amountIn Amount of the input token to swap
            /// @param recipient Address to receive the output tokens
            /// @param tokenOut Address of the output token
            /// @param amountOutMin Minimum acceptable amount of output tokens (slippage protection)
            /// @param executor Address of the executor contract to perform the swap logic
            /// @param executorData Encoded data for the executor call
            /// @return amountOut The actual amount of output tokens received
            function snwap(
              address tokenIn,
              uint256 amountIn,
              address recipient,
              address tokenOut,
              uint256 amountOutMin,
              address executor,
              bytes calldata executorData
            ) external onlyTrusted returns (uint256 amountOut) {
               // Pre-fund RedSnwapper with input tokens
               _safeTransfer(tokenIn, address(redSnwapper), amountIn);
              // Execute snwap with zero amountIn
              amountOut = redSnwapper.snwap(
                tokenIn,
                0,
                recipient,
                tokenOut,
                amountOutMin,
                executor,
                executorData
              );
            }
            /// @notice Performs multiple swaps via the configured RedSnwapper
            /// @dev Must be called by a trusted operator
            /// @param inputTokens Array of input token parameters
            /// @param outputTokens Array of output token requirements
            /// @param executors Array of executor calls to perform
            /// @return amountOut Array of actual amounts of output tokens received
            function snwapMultiple(
              IRedSnwapper.InputToken[] calldata inputTokens,
              IRedSnwapper.OutputToken[] calldata outputTokens,
              IRedSnwapper.Executor[] calldata executors
            ) external onlyTrusted returns (uint256[] memory amountOut) {
             uint256 length = inputTokens.length;
              IRedSnwapper.InputToken[] memory _inputTokens = new IRedSnwapper.InputToken[](length);
              for (uint256 i = 0; i < length; ++i) {
                  // Pre-fund RedSnwapper with input tokens
                  _safeTransfer(
                      inputTokens[i].token,
                      address(redSnwapper),
                      inputTokens[i].amountIn
                  );
                  // Build _inputTokens with zero amountIn
                  _inputTokens[i] = IRedSnwapper.InputToken({
                      token: inputTokens[i].token,
                      amountIn: 0,
                      transferTo: inputTokens[i].transferTo
                  });
              }
              // Execute snwapMultiple
              amountOut = redSnwapper.snwapMultiple(
                  _inputTokens,
                  outputTokens,
                  executors
              );
            }
            /// @notice Withdraw any token or eth from the contract
            /// @dev can only be called by owner
            /// @param token The address of the token to be withdrawn, 0x0 for eth
            /// @param to The address to send the token to
            /// @param _value The amount of the token to be withdrawn
            function withdraw(address token, address to, uint256 _value) onlyOwner external {
              if (token != address(0)) {
                _safeTransfer(token, to, _value);
              } 
              else {
                (bool success, ) = to.call{value: _value}("");
                require(success);
              }
            }
            
            function _safeTransfer(address token, address to, uint value) internal {
              (bool success, bytes memory data) = token.call(abi.encodeWithSelector(TRANSFER_SELECTOR, to, value));
              if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferFailed();
            }
            /// @notice In case we receive any unwrapped eth (native token) we can call this
            /// @dev operators can call this 
            function wrapEth() onlyTrusted external {
              weth.call{value: address(this).balance}("");
            }
            /// @notice Available function in case we need to do any calls that aren't supported by the contract (unwinding lp positions, etc.)
            /// @dev can only be called by owner
            /// @param to The address to send the call to
            /// @param _value The amount of eth to send with the call
            /// @param data The data to be sent with the call
            function doAction(address to, uint256 _value, bytes memory data) onlyOwner external {
              (bool success, ) = to.call{value: _value}(data);
              require(success);
            }
            receive() external payable {}
          }